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:

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

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: 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))
>>> 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))
M = Manifold(2, 'S^2', structure='topological') # the 2-dimensional sphere S^2
U = M.open_subset('U') # complement of the North pole
c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
V = M.open_subset('V') # complement of the South pole
c_uv.<u,v> = V.chart() # 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^2+y^2), y/(x^2+y^2)),
                               intersection_name='W',
                               restrictions1=x^2+y^2!=0,
                               restrictions2=u^2+v^2!=0)
uv_to_xy = xy_to_uv.inverse()
N = Manifold(3, 'R^3', latex_name=r'\RR^3', structure='topological')  # R^3
c_cart.<X,Y,Z> = N.chart()  # Cartesian coordinates on R^3
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')
Phi
Phi.parent()
Phi.parent() is Hom(M, N)
type(Phi)
Phi.display()

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

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

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: 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))
>>> 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))
Phi1.display()

The definition can be completed by using 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))
>>> 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))
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)])
Phi1.display()

At this stage, Phi1 and Phi are fully equivalent:

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

The map acts on points:

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)
>>> 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)
np = M.point((0,0), chart=c_uv)  # the North pole
Phi(np)
Phi(np).coord()  # Cartesian coordinates
sp = M.point((0,0), chart=c_xy)  # the South pole
Phi(sp).coord()  # Cartesian coordinates

The test suite is passed:

sage: TestSuite(Phi).run()
sage: TestSuite(Phi1).run()
>>> from sage.all import *
>>> TestSuite(Phi).run()
>>> TestSuite(Phi1).run()
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: 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))
>>> 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))
P = Manifold(2, 'R^2', latex_name=r'\RR^2', structure='topological') # R^2 (equatorial plane)
cP.<xP, yP> = P.chart()
Psi = N.continuous_map(P, (X/(1-Z), Y/(1-Z)), name='Psi',
                     latex_name=r'\Psi')
Psi
Psi.display()

Then we compose Psi with Phi, thereby getting a map \(S^2 \to \RR^2\):

sage: ster = Psi * Phi ; ster
Continuous map from the 2-dimensional topological manifold S^2
 to the 2-dimensional topological manifold R^2
>>> 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
ster = Psi * Phi ; ster

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
>>> from sage.all import *
>>> ster(sp) == Psi(Phi(sp))
True
ster(sp) == Psi(Phi(sp))

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))
>>> 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))
ster.display()

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: 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
>>> 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
N = Manifold(1, 'N', structure='topological')
c_N = N.chart('X')
Phi = M.continuous_map(N, {(c_xy, c_N): x^2+y^2,
                           (c_uv, c_N): 1/(u^2+v^2)})
Psi = M.continuous_map(N, {(c_xy, c_N): [x^2+y^2],
                           (c_uv, c_N): [1/(u^2+v^2)]})
Phi == Psi

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

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))
>>> 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))
R = Manifold(1, 'R', structure='topological')  # field R
T.<t> = R.chart()  # canonical chart on R
R2 = Manifold(2, 'R^2', structure='topological')  # R^2
c_xy.<x,y> = R2.chart() # Cartesian coordinates on R^2
Phi = R.continuous_map(R2, [cos(t), sin(t)], name='Phi'); Phi
Phi.parent()
Phi.parent() is Hom(R, R2)
Phi.display()

An example of homeomorphism 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.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))
>>> 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))
D = R2.open_subset('D', coord_def={c_xy: x^2+y^2<1}) # the open unit disk
Phi = D.homeomorphism(R2, [x/sqrt(1-x^2-y^2), y/sqrt(1-x^2-y^2)],
                      name='Phi', latex_name=r'\Phi')
Phi
Phi.parent()
Phi.parent() is Hom(D, R2)
Phi.display()

The image of a point:

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)
>>> 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)
p = D.point((1/2,0))
q = Phi(p) ; q
q.coord()

The inverse homeomorphism is computed by inverse():

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))
>>> 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))
Phi.inverse()
Phi.inverse().display()

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
>>> from sage.all import *
>>> Phi**(-Integer(1)) is Phi.inverse()
True
>>> ~Phi is Phi.inverse()
True
Phi^(-1) is Phi.inverse()
~Phi is Phi.inverse()

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
>>> from sage.all import *
>>> (~Phi)(q) == p
True
>>> Phi * ~Phi == R2.identity_map()
True
>>> ~Phi * Phi == D.identity_map()
True
(~Phi)(q) == p
Phi * ~Phi == R2.identity_map()
~Phi * Phi == D.identity_map()

The coordinate expression of the inverse homeomorphism:

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))
>>> 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))
(~Phi).display()

A special case of homeomorphism: 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 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
>>> 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
id = D.identity_map() ; id
latex(id)
id.parent()
id.parent() is Hom(D, D)
id is Hom(D,D).one()  # the identity element of the monoid Hom(D,D)

The identity map acting on a point:

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

The coordinate expression of the identity map:

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

The identity map is its own inverse:

sage: id^(-1) is id
True
sage: ~id is id
True
>>> from sage.all import *
>>> id**(-Integer(1)) is id
True
>>> ~id is id
True
id^(-1) is id
~id is id
add_expr(chart1, chart2, coord_functions)[source]

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

We construct the links between spherical coordinates and Cartesian ones:

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)
>>> 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)
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))
rot = U.continuous_map(U, ((x - sqrt(3)*y)/2, (sqrt(3)*x + y)/2),
                       name='R')
rot.display(c_cart, c_cart)

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

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))
>>> 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))
rot.display(c_spher, c_spher)

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

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)
>>> 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)
rot.add_expr(c_spher, c_spher, (r, ph+pi/3))
rot.display(c_spher, c_spher)

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: 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))}
>>> 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))}
rot._coord_expression # random (dictionary output)

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

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))}
>>> 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))}
rot.set_expr(c_spher, c_spher, (r, ph+pi/3))
rot._coord_expression

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

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))}
>>> 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))}
rot.display(c_cart, c_cart)
rot._coord_expression # random (dictionary output)

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

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
>>> 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
p = M.point((1,2))  #  p defined by its Cartesian coord.
q = rot(p)  # q is computed by means of Cartesian coord.
p1 = M.point((sqrt(5), arctan(2)), chart=c_spher) # p1 is defined only in terms of c_spher
q1 = rot(p1) # computation by means of spherical coordinates
q1 == q
add_expression(chart1, chart2, coord_functions)[source]

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

We construct the links between spherical coordinates and Cartesian ones:

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)
>>> 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)
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))
rot = U.continuous_map(U, ((x - sqrt(3)*y)/2, (sqrt(3)*x + y)/2),
                       name='R')
rot.display(c_cart, c_cart)

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

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))
>>> 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))
rot.display(c_spher, c_spher)

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

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)
>>> 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)
rot.add_expr(c_spher, c_spher, (r, ph+pi/3))
rot.display(c_spher, c_spher)

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: 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))}
>>> 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))}
rot._coord_expression # random (dictionary output)

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

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))}
>>> 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))}
rot.set_expr(c_spher, c_spher, (r, ph+pi/3))
rot._coord_expression

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

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))}
>>> 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))}
rot.display(c_cart, c_cart)
rot._coord_expression # random (dictionary output)

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

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
>>> 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
p = M.point((1,2))  #  p defined by its Cartesian coord.
q = rot(p)  # q is computed by means of Cartesian coord.
p1 = M.point((sqrt(5), arctan(2)), chart=c_spher) # p1 is defined only in terms of c_spher
q1 = rot(p1) # computation by means of spherical coordinates
q1 == q
coord_functions(chart1=None, chart2=None)[source]

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:

EXAMPLES:

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

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'>
>>> 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'>
M = Manifold(2, 'M', structure='topological')
N = Manifold(3, 'N', structure='topological')
c_uv.<u,v> = M.chart()
c_xyz.<x,y,z> = N.chart()
Phi = M.continuous_map(N, (u*v, u/v, u+v), name='Phi',
                       latex_name=r'\Phi')
Phi.display()
Phi.coord_functions(c_uv, c_xyz)
Phi.coord_functions() # equivalent to above since 'uv' and 'xyz' are default charts
type(Phi.coord_functions())

Coordinate representation in other charts:

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))
>>> 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))
c_UV.<U,V> = M.chart()  # new chart on M
ch_uv_UV = c_uv.transition_map(c_UV, [u-v, u+v])
ch_uv_UV.inverse()(U,V)
c_XYZ.<X,Y,Z> = N.chart() # new chart on N
ch_xyz_XYZ = c_xyz.transition_map(c_XYZ,
                                  [2*x-3*y+z, y+z-x, -x+2*y-z])
ch_xyz_XYZ.inverse()(X,Y,Z)
Phi.coord_functions(c_UV, c_xyz)
Phi.coord_functions(c_uv, c_XYZ)
Phi.coord_functions(c_UV, c_XYZ)

Coordinate representation with respect to a subchart in the domain:

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))
>>> 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))
A = M.open_subset('A', coord_def={c_uv: u>0})
Phi.coord_functions(c_uv.restrict(A), c_xyz)

Coordinate representation with respect to a superchart in the codomain:

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))
>>> 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))
B = N.open_subset('B', coord_def={c_xyz: x<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
Phi1.coord_functions(c_uv, c_xyz) # c_xyz = superchart of c_xyz_B

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

sage: Phi1.coord_functions(c_uv.restrict(A), c_xyz)
Coordinate functions (u*v, u/v, u + v) on the Chart (A, (u, v))
>>> 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))
Phi1.coord_functions(c_uv.restrict(A), c_xyz)

Same example with SymPy as the symbolic calculus engine:

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))
>>> 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))
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)
Phi.coord_functions(c_UV, c_xyz)
Phi.coord_functions(c_UV, c_XYZ)
disp(chart1=None, chart2=None)[source]

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: 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}
>>> 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}
R.<t> = manifolds.RealLine()
I = R.open_interval(0, 2*pi)
J = R.open_interval(2*pi, 6*pi)
h = J.continuous_map(I, ((t-2*pi)/2,), name='h')
h.display()
latex(h.display())

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

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))
>>> 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))
M = Manifold(2, 'S^2', structure='topological') # the 2-dimensional sphere S^2
U = M.open_subset('U') # complement of the North pole
c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
V = M.open_subset('V') # complement of the South pole
c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
M.declare_union(U,V)   # S^2 is the union of U and V
N = Manifold(3, 'R^3', latex_name=r'\RR^3', structure='topological')  # R^3
c_cart.<X,Y,Z> = N.chart()  # Cartesian coordinates on R^3
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')
Phi.display(c_xy, c_cart)
Phi.display(c_uv, c_cart)

The LaTeX output of that embedding is:

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}
>>> 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}
latex(Phi.display(c_xy, c_cart))

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

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

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

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

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))
>>> 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))
Phi.restrict(U).display()

A shortcut of display() is disp():

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

Display when SymPy is the symbolic engine:

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}
>>> 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}
M.set_calculus_method('sympy')
N.set_calculus_method('sympy')
Phi.display(c_xy, c_cart)
latex(Phi.display(c_xy, c_cart))
display(chart1=None, chart2=None)[source]

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: 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}
>>> 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}
R.<t> = manifolds.RealLine()
I = R.open_interval(0, 2*pi)
J = R.open_interval(2*pi, 6*pi)
h = J.continuous_map(I, ((t-2*pi)/2,), name='h')
h.display()
latex(h.display())

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

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))
>>> 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))
M = Manifold(2, 'S^2', structure='topological') # the 2-dimensional sphere S^2
U = M.open_subset('U') # complement of the North pole
c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
V = M.open_subset('V') # complement of the South pole
c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
M.declare_union(U,V)   # S^2 is the union of U and V
N = Manifold(3, 'R^3', latex_name=r'\RR^3', structure='topological')  # R^3
c_cart.<X,Y,Z> = N.chart()  # Cartesian coordinates on R^3
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')
Phi.display(c_xy, c_cart)
Phi.display(c_uv, c_cart)

The LaTeX output of that embedding is:

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}
>>> 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}
latex(Phi.display(c_xy, c_cart))

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

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

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

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

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))
>>> 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))
Phi.restrict(U).display()

A shortcut of display() is disp():

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

Display when SymPy is the symbolic engine:

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}
>>> 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}
M.set_calculus_method('sympy')
N.set_calculus_method('sympy')
Phi.display(c_xy, c_cart)
latex(Phi.display(c_xy, c_cart))
expr(chart1=None, chart2=None)[source]

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: 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'>
>>> 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'>
M = Manifold(2, 'M', structure='topological')
N = Manifold(3, 'N', structure='topological')
c_uv.<u,v> = M.chart()
c_xyz.<x,y,z> = N.chart()
Phi = M.continuous_map(N, (u*v, u/v, u+v), name='Phi',
                       latex_name=r'\Phi')
Phi.display()
Phi.expr(c_uv, c_xyz)
Phi.expr()  # equivalent to above since 'uv' and 'xyz' are default charts
type(Phi.expr()[0])

Expressions in other charts:

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))
>>> 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))
c_UV.<U,V> = M.chart()  # new chart on M
ch_uv_UV = c_uv.transition_map(c_UV, [u-v, u+v])
ch_uv_UV.inverse()(U,V)
c_XYZ.<X,Y,Z> = N.chart() # new chart on N
ch_xyz_XYZ = c_xyz.transition_map(c_XYZ,
                                  [2*x-3*y+z, y+z-x, -x+2*y-z])
ch_xyz_XYZ.inverse()(X,Y,Z)
Phi.expr(c_UV, c_xyz)
Phi.expr(c_uv, c_XYZ)
Phi.expr(c_UV, c_XYZ)

A rotation in some Euclidean plane:

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

Expression of the rotation in terms of Cartesian coordinates:

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)
>>> 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)
c_cart.<x,y> = M.chart() # 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^2+y^2), atan2(y,x))
rot.expr(c_cart, c_cart)
expression(chart1=None, chart2=None)[source]

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: 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'>
>>> 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'>
M = Manifold(2, 'M', structure='topological')
N = Manifold(3, 'N', structure='topological')
c_uv.<u,v> = M.chart()
c_xyz.<x,y,z> = N.chart()
Phi = M.continuous_map(N, (u*v, u/v, u+v), name='Phi',
                       latex_name=r'\Phi')
Phi.display()
Phi.expr(c_uv, c_xyz)
Phi.expr()  # equivalent to above since 'uv' and 'xyz' are default charts
type(Phi.expr()[0])

Expressions in other charts:

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))
>>> 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))
c_UV.<U,V> = M.chart()  # new chart on M
ch_uv_UV = c_uv.transition_map(c_UV, [u-v, u+v])
ch_uv_UV.inverse()(U,V)
c_XYZ.<X,Y,Z> = N.chart() # new chart on N
ch_xyz_XYZ = c_xyz.transition_map(c_XYZ,
                                  [2*x-3*y+z, y+z-x, -x+2*y-z])
ch_xyz_XYZ.inverse()(X,Y,Z)
Phi.expr(c_UV, c_xyz)
Phi.expr(c_uv, c_XYZ)
Phi.expr(c_UV, c_XYZ)

A rotation in some Euclidean plane:

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

Expression of the rotation in terms of Cartesian coordinates:

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)
>>> 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)
c_cart.<x,y> = M.chart() # 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^2+y^2), atan2(y,x))
rot.expr(c_cart, c_cart)
image(subset=None, inverse=None)[source]

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: 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
>>> 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
M = Manifold(2, 'M', structure='topological')
N = Manifold(1, 'N', ambient=M, structure='topological')
CM.<x,y> = M.chart()
CN.<u> = N.chart(coord_restrictions=lambda u: [u > -1, u < 1])
Phi = N.continuous_map(M, {(CN,CM): [u, u^2]}, name='Phi')
Phi.image()
S = N.subset('S')
Phi_S = Phi.image(S); Phi_S
Phi_S.is_subset(M)
inverse()[source]

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

A pi/3 rotation around the origin:

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)
>>> 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)
rot = M.homeomorphism(M, ((x - sqrt(3)*y)/2, (sqrt(3)*x + y)/2),
                      name='R')
rot.inverse()
rot.inverse().display()

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

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
>>> 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
(a, b) = var('a b')
p = M.point((a,b)) # a generic point on M
q = rot(p)
p1 = rot.inverse()(q)
p1 == p

The result is cached:

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

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

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

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

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)
>>> 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)
M = Manifold(2, 'M', structure='topological') # the 2-dimensional sphere S^2
U = M.open_subset('U') # complement of the North pole
c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
V = M.open_subset('V') # complement of the South pole
c_uv.<u,v> = V.chart() # 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^2+y^2), y/(x^2+y^2)),
                               intersection_name='W',
                               restrictions1=x^2+y^2!=0,
                               restrictions2=u^2+v^2!=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()
si = s.inverse(); si
si.display()

The equatorial symmetry is of course an involution:

sage: si == s
True
>>> from sage.all import *
>>> si == s
True
si == s
is_identity()[source]

Check whether self is an identity map.

EXAMPLES:

Tests on continuous maps of a 2-dimensional manifold:

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
>>> 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
M = Manifold(2, 'M', structure='topological')
X.<x,y> = M.chart()
M.identity_map().is_identity()  # obviously...
Hom(M, M).one().is_identity()  # a variant of the obvious
a = M.continuous_map(M, coord_functions={(X,X): (x, y)})
a.is_identity()
a = M.continuous_map(M, coord_functions={(X,X): (x, y+1)})
a.is_identity()

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

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
>>> 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
N = Manifold(2, 'N', structure='topological')
Y.<u,v> = N.chart()
a = M.continuous_map(N, {(X,Y): (x, y)})
a.display()
a.is_identity()
preimage(codomain_subset, name=None, latex_name=None)[source]

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:

EXAMPLES:

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
>>> 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
R = Manifold(1, 'R', structure='topological')  # field R
T.<t> = R.chart()  # canonical chart on R
R2 = Manifold(2, 'R^2', structure='topological')  # R^2
c_xy.<x,y> = R2.chart() # Cartesian coordinates on R^2
Phi = R.continuous_map(R2, [cos(t), sin(t)], name='Phi'); Phi
Q1 = R2.open_subset('Q1', coord_def={c_xy: [x>0, y>0]}); Q1
Phi_inv_Q1 = Phi.preimage(Q1); Phi_inv_Q1
R.point([pi/4]) in Phi_inv_Q1
R.point([0]) in Phi_inv_Q1
R.point([3*pi/4]) in Phi_inv_Q1

The identity map is handled specially:

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
>>> 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
M = Manifold(2, 'M', structure='topological')
X.<x,y> = M.chart()
M.identity_map().preimage(M)
M.identity_map().preimage(M) is M

Another trivial case:

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
>>> 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
M = Manifold(2, 'M', structure='topological')
X.<x,y> = M.chart()
D1 = M.open_subset('D1', coord_def={X: x^2+y^2<1}) # the open unit disk
D2 = M.open_subset('D2', coord_def={X: x^2+y^2<4})
f = Hom(D1,D2)({(X.restrict(D1), X.restrict(D2)): (2*x, 2*y)}, name='f')
f.preimage(D2)
f.preimage(M)
pullback(codomain_subset, name=None, latex_name=None)[source]

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:

EXAMPLES:

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
>>> 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
R = Manifold(1, 'R', structure='topological')  # field R
T.<t> = R.chart()  # canonical chart on R
R2 = Manifold(2, 'R^2', structure='topological')  # R^2
c_xy.<x,y> = R2.chart() # Cartesian coordinates on R^2
Phi = R.continuous_map(R2, [cos(t), sin(t)], name='Phi'); Phi
Q1 = R2.open_subset('Q1', coord_def={c_xy: [x>0, y>0]}); Q1
Phi_inv_Q1 = Phi.preimage(Q1); Phi_inv_Q1
R.point([pi/4]) in Phi_inv_Q1
R.point([0]) in Phi_inv_Q1
R.point([3*pi/4]) in Phi_inv_Q1

The identity map is handled specially:

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
>>> 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
M = Manifold(2, 'M', structure='topological')
X.<x,y> = M.chart()
M.identity_map().preimage(M)
M.identity_map().preimage(M) is M

Another trivial case:

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
>>> 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
M = Manifold(2, 'M', structure='topological')
X.<x,y> = M.chart()
D1 = M.open_subset('D1', coord_def={X: x^2+y^2<1}) # the open unit disk
D2 = M.open_subset('D2', coord_def={X: x^2+y^2<4})
f = Hom(D1,D2)({(X.restrict(D1), X.restrict(D2)): (2*x, 2*y)}, name='f')
f.preimage(D2)
f.preimage(M)
restrict(subdomain, subcodomain=None)[source]

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

INPUT:

  • subdomainTopologicalManifold; 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:

EXAMPLES:

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

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))
>>> 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))
M = Manifold(2, 'R^2', structure='topological')  # R^2
c_xy.<x,y> = M.chart()  # Cartesian coord. on R^2
D = M.open_subset('D', coord_def={c_xy: x^2+y^2<1}) # the open unit disk
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')
Phi.display()
c_xy_D = c_xy.restrict(D)
U = D.open_subset('U', coord_def={c_xy_D: x^2+y^2>1/2}) # the annulus 1/2 < r < 1
Phi.restrict(U)
Phi.restrict(U).parent()
Phi.domain()
Phi.restrict(U).domain()
Phi.restrict(U).display()

The result is cached:

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

The restriction of the identity map:

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
>>> 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
id = D.identity_map() ; id
id.restrict(U)
id.restrict(U) is U.identity_map()

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

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
>>> 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
Phi = D.continuous_map(M, [x/sqrt(1+x^2+y^2), y/sqrt(1+x^2+y^2)])
Phi
Phi.restrict(D, subcodomain=D)
set_expr(chart1, chart2, coord_functions)[source]

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

Links between spherical coordinates and Cartesian ones:

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)
>>> 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)
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))
rot = U.continuous_map(U, ((x - sqrt(3)*y)/2, (sqrt(3)*x + y)/2),
                       name='R')
rot.display(c_cart, c_cart)

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

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)
>>> 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)
rot.set_expr(c_spher, c_spher, (r, ph+pi/3))
rot.display(c_spher, c_spher)

The expression in Cartesian coordinates has been erased:

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))}
>>> 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))}
rot._coord_expression

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

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))}
>>> 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))}
rot.display(c_cart, c_cart)
rot._coord_expression  # random (dictionary output)
set_expression(chart1, chart2, coord_functions)[source]

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

Links between spherical coordinates and Cartesian ones:

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)
>>> 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)
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))
rot = U.continuous_map(U, ((x - sqrt(3)*y)/2, (sqrt(3)*x + y)/2),
                       name='R')
rot.display(c_cart, c_cart)

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

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)
>>> 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)
rot.set_expr(c_spher, c_spher, (r, ph+pi/3))
rot.display(c_spher, c_spher)

The expression in Cartesian coordinates has been erased:

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))}
>>> 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))}
rot._coord_expression

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

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))}
>>> 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))}
rot.display(c_cart, c_cart)
rot._coord_expression  # random (dictionary output)