Topological Manifolds

Given a topological field \(K\) (in most applications, \(K = \RR\) or \(K = \CC\)) and a non-negative integer \(n\), a topological manifold of dimension \(n\) over K is a topological space \(M\) such that

  • \(M\) is a Hausdorff space,

  • \(M\) is second countable,

  • every point in \(M\) has a neighborhood homeomorphic to \(K^n\).

Topological manifolds are implemented via the class TopologicalManifold. Open subsets of topological manifolds are also implemented via TopologicalManifold, since they are topological manifolds by themselves.

In the current setting, topological manifolds are mostly described by means of charts (see Chart).

TopologicalManifold serves as a base class for more specific manifold classes.

The user interface is provided by the generic function Manifold(), with with the argument structure set to 'topological'.

Example 1: the 2-sphere as a topological manifold of dimension 2 over \(\RR\)

One starts by declaring \(S^2\) as a 2-dimensional topological manifold:

sage: M = Manifold(2, 'S^2', structure='topological')
sage: M
2-dimensional topological manifold S^2

Since the base topological field has not been specified in the argument list of Manifold, \(\RR\) is assumed:

sage: M.base_field()
Real Field with 53 bits of precision
sage: dim(M)
2

Let us consider the complement of a point, the “North pole” say; this is an open subset of \(S^2\), which we call \(U\):

sage: U = M.open_subset('U'); U
Open subset U of the 2-dimensional topological manifold S^2

A standard chart on \(U\) is provided by the stereographic projection from the North pole to the equatorial plane:

sage: stereoN.<x,y> = U.chart(); stereoN
Chart (U, (x, y))

Thanks to the operator <x,y> on the left-hand side, the coordinates declared in a chart (here \(x\) and \(y\)), are accessible by their names; they are Sage’s symbolic variables:

sage: y
y
sage: type(y)
<type 'sage.symbolic.expression.Expression'>

The South pole is the point of coordinates \((x, y) = (0, 0)\) in the above chart:

sage: S = U.point((0,0), chart=stereoN, name='S'); S
Point S on the 2-dimensional topological manifold S^2

Let us call \(V\) the open subset that is the complement of the South pole and let us introduce on it the chart induced by the stereographic projection from the South pole to the equatorial plane:

sage: V = M.open_subset('V'); V
Open subset V of the 2-dimensional topological manifold S^2
sage: stereoS.<u,v> = V.chart(); stereoS
Chart (V, (u, v))

The North pole is the point of coordinates \((u, v) = (0, 0)\) in this chart:

sage: N = V.point((0,0), chart=stereoS, name='N'); N
Point N on the 2-dimensional topological manifold S^2

To fully construct the manifold, we declare that it is the union of \(U\) and \(V\):

sage: M.declare_union(U,V)

and we provide the transition map between the charts stereoN = \((U, (x, y))\) and stereoS = \((V, (u, v))\), denoting by \(W\) the intersection of \(U\) and \(V\) (\(W\) is the subset of \(U\) defined by \(x^2 + y^2 \neq 0\), as well as the subset of \(V\) defined by \(u^2 + v^2 \neq 0\)):

sage: stereoN_to_S = stereoN.transition_map(stereoS, [x/(x^2+y^2), y/(x^2+y^2)],
....:                          intersection_name='W', restrictions1= x^2+y^2!=0,
....:                                                 restrictions2= u^2+v^2!=0)
sage: stereoN_to_S
Change of coordinates from Chart (W, (x, y)) to Chart (W, (u, v))
sage: stereoN_to_S.display()
u = x/(x^2 + y^2)
v = y/(x^2 + y^2)

We give the name W to the Python variable representing \(W = U \cap V\):

sage: W = U.intersection(V)

The inverse of the transition map is computed by the method sage.manifolds.chart.CoordChange.inverse():

sage: stereoN_to_S.inverse()
Change of coordinates from Chart (W, (u, v)) to Chart (W, (x, y))
sage: stereoN_to_S.inverse().display()
x = u/(u^2 + v^2)
y = v/(u^2 + v^2)

At this stage, we have four open subsets on \(S^2\):

sage: M.subset_family()
Set {S^2, U, V, W} of open subsets of the 2-dimensional topological manifold S^2

\(W\) is the open subset that is the complement of the two poles:

sage: N in W or S in W
False

The North pole lies in \(V\) and the South pole in \(U\):

sage: N in V, N in U
(True, False)
sage: S in U, S in V
(True, False)

The manifold’s (user) atlas contains four charts, two of them being restrictions of charts to a smaller domain:

sage: M.atlas()
[Chart (U, (x, y)), Chart (V, (u, v)),
 Chart (W, (x, y)), Chart (W, (u, v))]

Let us consider the point of coordinates \((1, 2)\) in the chart stereoN:

sage: p = M.point((1,2), chart=stereoN, name='p'); p
Point p on the 2-dimensional topological manifold S^2
sage: p.parent()
2-dimensional topological manifold S^2
sage: p in W
True

The coordinates of \(p\) in the chart stereoS are computed by letting the chart act on the point:

sage: stereoS(p)
(1/5, 2/5)

Given the definition of \(p\), we have of course:

sage: stereoN(p)
(1, 2)

Similarly:

sage: stereoS(N)
(0, 0)
sage: stereoN(S)
(0, 0)

A continuous map \(S^2 \to \RR\) (scalar field):

sage: f = M.scalar_field({stereoN: atan(x^2+y^2), stereoS: pi/2-atan(u^2+v^2)},
....:                    name='f')
sage: f
Scalar field f on the 2-dimensional topological manifold S^2
sage: f.display()
f: S^2 → ℝ
on U: (x, y) ↦ arctan(x^2 + y^2)
on V: (u, v) ↦ 1/2*pi - arctan(u^2 + v^2)
sage: f(p)
arctan(5)
sage: f(N)
1/2*pi
sage: f(S)
0
sage: f.parent()
Algebra of scalar fields on the 2-dimensional topological manifold S^2
sage: f.parent().category()
Join of Category of commutative algebras over Symbolic Ring and Category of homsets of topological spaces

Example 2: the Riemann sphere as a topological manifold of dimension 1 over \(\CC\)

We declare the Riemann sphere \(\CC^*\) as a 1-dimensional topological manifold over \(\CC\):

sage: M = Manifold(1, 'ℂ*', structure='topological', field='complex'); M
Complex 1-dimensional topological manifold ℂ*

We introduce a first open subset, which is actually \(\CC = \CC^*\setminus\{\infty\}\) if we interpret \(\CC^*\) as the Alexandroff one-point compactification of \(\CC\):

sage: U = M.open_subset('U')

A natural chart on \(U\) is then nothing but the identity map of \(\CC\), hence we denote the associated coordinate by \(z\):

sage: Z.<z> = U.chart()

The origin of the complex plane is the point of coordinate \(z = 0\):

sage: O = U.point((0,), chart=Z, name='O'); O
Point O on the Complex 1-dimensional topological manifold ℂ*

Another open subset of \(\CC^*\) is \(V = \CC^*\setminus\{O\}\):

sage: V = M.open_subset('V')

We define a chart on \(V\) such that the point at infinity is the point of coordinate \(0\) in this chart:

sage: W.<w> = V.chart(); W
Chart (V, (w,))
sage: inf = M.point((0,), chart=W, name='inf', latex_name=r'\infty')
sage: inf
Point inf on the Complex 1-dimensional topological manifold ℂ*

To fully construct the Riemann sphere, we declare that it is the union of \(U\) and \(V\):

sage: M.declare_union(U,V)

and we provide the transition map between the two charts as \(w = 1 / z\) on \(A = U \cap V\):

sage: Z_to_W = Z.transition_map(W, 1/z, intersection_name='A',
....:                           restrictions1= z!=0, restrictions2= w!=0)
sage: Z_to_W
Change of coordinates from Chart (A, (z,)) to Chart (A, (w,))
sage: Z_to_W.display()
w = 1/z
sage: Z_to_W.inverse()
Change of coordinates from Chart (A, (w,)) to Chart (A, (z,))
sage: Z_to_W.inverse().display()
z = 1/w

Let consider the complex number \(i\) as a point of the Riemann sphere:

sage: i = M((I,), chart=Z, name='i'); i
Point i on the Complex 1-dimensional topological manifold ℂ*

Its coordinates w.r.t. the charts Z and W are:

sage: Z(i)
(I,)
sage: W(i)
(-I,)

and we have:

sage: i in U
True
sage: i in V
True

The following subsets and charts have been defined:

sage: M.subset_family()
Set {A, U, V, ℂ*} of open subsets of the Complex 1-dimensional topological manifold ℂ*
sage: M.atlas()
[Chart (U, (z,)), Chart (V, (w,)), Chart (A, (z,)), Chart (A, (w,))]

A constant map \(\CC^* \rightarrow \CC\):

sage: f = M.constant_scalar_field(3+2*I, name='f'); f
Scalar field f on the Complex 1-dimensional topological manifold ℂ*
sage: f.display()
f: ℂ* → ℂ
on U: z ↦ 2*I + 3
on V: w ↦ 2*I + 3
sage: f(O)
2*I + 3
sage: f(i)
2*I + 3
sage: f(inf)
2*I + 3
sage: f.parent()
Algebra of scalar fields on the Complex 1-dimensional topological
 manifold ℂ*
sage: f.parent().category()
Join of Category of commutative algebras over Symbolic Ring and Category of homsets of topological spaces

AUTHORS:

REFERENCES:

sage.manifolds.manifold.Manifold(dim, name, latex_name=None, field='real', structure='smooth', start_index=0, **extra_kwds)

Construct a manifold of a given type over a topological field.

Given a topological field \(K\) (in most applications, \(K = \RR\) or \(K = \CC\)) and a non-negative integer \(n\), a topological manifold of dimension \(n\) over K is a topological space \(M\) such that

  • \(M\) is a Hausdorff space,

  • \(M\) is second countable, and

  • every point in \(M\) has a neighborhood homeomorphic to \(K^n\).

A real manifold is a manifold over \(\RR\). A differentiable (resp. smooth, resp. analytic) manifold is a manifold such that all transition maps are differentiable (resp. smooth, resp. analytic). A pseudo-Riemannian manifold is a real differentiable manifold equipped with a metric tensor \(g\) (i.e. a field of non-degenerate symmetric bilinear forms), with the two subcases of Riemannian manifold (\(g\) positive-definite) and Lorentzian manifold (\(g\) has signature \(n-2\) or \(2-n\)).

INPUT:

  • dim – positive integer; dimension of the manifold

  • name – string; name (symbol) given to the manifold

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

  • field – (default: 'real') field \(K\) on which the manifold is defined; allowed values are

    • 'real' or an object of type RealField (e.g. RR) for a manifold over \(\RR\)

    • 'complex' or an object of type ComplexField (e.g. CC) for a manifold over \(\CC\)

    • an object in the category of topological fields (see Fields and TopologicalSpaces) for other types of manifolds

  • structure – (default: 'smooth') to specify the structure or type of manifold; allowed values are

    • 'topological' or 'top' for a topological manifold

    • 'differentiable' or 'diff' for a differentiable manifold

    • 'smooth' for a smooth manifold

    • 'analytic' for an analytic manifold

    • 'pseudo-Riemannian' for a real differentiable manifold equipped with a pseudo-Riemannian metric; the signature is specified via the keyword argument signature (see below)

    • 'Riemannian' for a real differentiable manifold equipped with a Riemannian (i.e. positive definite) metric

    • 'Lorentzian' for a real differentiable manifold equipped with a Lorentzian metric; the signature convention is specified by the keyword argument signature='positive' (default) or 'negative'

  • start_index – (default: 0) integer; lower value of the range of indices used for “indexed objects” on the manifold, e.g. coordinates in a chart

  • extra_kwds – keywords meaningful only for some specific types of manifolds:

    • diff_degree – (only for differentiable manifolds; default: infinity): the degree of differentiability

    • ambient – (only to construct a submanifold): the ambient manifold

    • metric_name – (only for pseudo-Riemannian manifolds; default: 'g') string; name (symbol) given to the metric

    • metric_latex_name – (only for pseudo-Riemannian manifolds; default: None) string; LaTeX symbol to denote the metric; if none is provided, the symbol is set to metric_name

    • signature – (only for pseudo-Riemannian manifolds; default: None) signature \(S\) of the metric as a single integer: \(S = n_+ - n_-\), where \(n_+\) (resp. \(n_-\)) is the number of positive terms (resp. negative terms) in any diagonal writing of the metric components; if signature is not provided, \(S\) is set to the manifold’s dimension (Riemannian signature); for Lorentzian manifolds the values signature='positive' (default) or signature='negative' are allowed to indicate the chosen signature convention.

OUTPUT:

EXAMPLES:

A 3-dimensional real topological manifold:

sage: M = Manifold(3, 'M', structure='topological'); M
3-dimensional topological manifold M

Given the default value of the parameter field, the above is equivalent to:

sage: M = Manifold(3, 'M', structure='topological', field='real'); M
3-dimensional topological manifold M

A complex topological manifold:

sage: M = Manifold(3, 'M', structure='topological', field='complex'); M
Complex 3-dimensional topological manifold M

A topological manifold over \(\QQ\):

sage: M = Manifold(3, 'M', structure='topological', field=QQ); M
3-dimensional topological manifold M over the Rational Field

A 3-dimensional real differentiable manifold of class \(C^4\):

sage: M = Manifold(3, 'M', field='real', structure='differentiable',
....:              diff_degree=4); M
3-dimensional differentiable manifold M

Since the default value of the parameter field is 'real', the above is equivalent to:

sage: M = Manifold(3, 'M', structure='differentiable', diff_degree=4)
sage: M
3-dimensional differentiable manifold M
sage: M.base_field_type()
'real'

A 3-dimensional real smooth manifold:

sage: M = Manifold(3, 'M', structure='differentiable', diff_degree=+oo)
sage: M
3-dimensional differentiable manifold M

Instead of structure='differentiable', diff_degree=+oo, it suffices to use structure='smooth' to get the same result:

sage: M = Manifold(3, 'M', structure='smooth'); M
3-dimensional differentiable manifold M
sage: M.diff_degree()
+Infinity

Actually, since 'smooth' is the default value of the parameter structure, the creation of a real smooth manifold can be shortened to:

sage: M = Manifold(3, 'M'); M
3-dimensional differentiable manifold M
sage: M.diff_degree()
+Infinity

For a complex smooth manifold, we have to set the parameter field:

sage: M = Manifold(3, 'M', field='complex'); M
3-dimensional complex manifold M
sage: M.diff_degree()
+Infinity

Submanifolds are constructed by means of the keyword ambient:

sage: N = Manifold(2, 'N', field='complex', ambient=M); N
2-dimensional differentiable submanifold N immersed in the
 3-dimensional complex manifold M

The immersion \(N\to M\) has to be specified in a second stage, via the method set_immersion() or set_embedding().

For more detailed examples, see the documentation of TopologicalManifold, DifferentiableManifold and PseudoRiemannianManifold, or the documentation of TopologicalSubmanifold, DifferentiableSubmanifold and PseudoRiemannianSubmanifold for submanifolds.

Uniqueness of manifold objects

Suppose we construct a manifold named \(M\):

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()

At some point, we change our mind and would like to restart with a new manifold, using the same name \(M\) and keeping the previous manifold for reference:

sage: M_old = M  # for reference
sage: M = Manifold(2, 'M', structure='topological')

This results in a brand new object:

sage: M.atlas()
[]

The object M_old is intact:

sage: M_old.atlas()
[Chart (M, (x, y))]

Both objects have the same display:

sage: M
2-dimensional topological manifold M
sage: M_old
2-dimensional topological manifold M

but they are different:

sage: M != M_old
True

Let us introduce a chart on M, using the same coordinate symbols as for M_old:

sage: X.<x,y> = M.chart()

The charts are displayed in the same way:

sage: M.atlas()
[Chart (M, (x, y))]
sage: M_old.atlas()
[Chart (M, (x, y))]

but they are actually different:

sage: M.atlas()[0] != M_old.atlas()[0]
True

Moreover, the two manifolds M and M_old are still considered distinct:

sage: M != M_old
True

This reflects the fact that the equality of manifold objects holds only for identical objects, i.e. one has M1 == M2 if, and only if, M1 is M2. Actually, the manifold classes inherit from WithEqualityById:

sage: isinstance(M, sage.misc.fast_methods.WithEqualityById)
True
class sage.manifolds.manifold.TopologicalManifold(n, name, field, structure, base_manifold=None, latex_name=None, start_index=0, category=None, unique_tag=None)

Bases: sage.manifolds.subset.ManifoldSubset

Topological manifold over a topological field \(K\).

Given a topological field \(K\) (in most applications, \(K = \RR\) or \(K = \CC\)) and a non-negative integer \(n\), a topological manifold of dimension \(n\) over K is a topological space \(M\) such that

  • \(M\) is a Hausdorff space,

  • \(M\) is second countable, and

  • every point in \(M\) has a neighborhood homeomorphic to \(K^n\).

This is a Sage parent class, the corresponding element class being ManifoldPoint.

INPUT:

  • n – positive integer; dimension of the manifold

  • name – string; name (symbol) given to the manifold

  • field – field \(K\) on which the manifold is defined; allowed values are

    • 'real' or an object of type RealField (e.g., RR) for a manifold over \(\RR\)

    • 'complex' or an object of type ComplexField (e.g., CC) for a manifold over \(\CC\)

    • an object in the category of topological fields (see Fields and TopologicalSpaces) for other types of manifolds

  • structure – manifold structure (see TopologicalStructure or RealTopologicalStructure)

  • base_manifold – (default: None) if not None, must be a topological manifold; the created object is then an open subset of base_manifold

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

  • start_index – (default: 0) integer; lower value of the range of indices used for “indexed objects” on the manifold, e.g., coordinates in a chart

  • category – (default: None) to specify the category; if None, Manifolds(field) is assumed (see the category Manifolds)

  • unique_tag – (default: None) tag used to force the construction of a new object when all the other arguments have been used previously (without unique_tag, the UniqueRepresentation behavior inherited from ManifoldSubset would return the previously constructed object corresponding to these arguments)

EXAMPLES:

A 4-dimensional topological manifold (over \(\RR\)):

sage: M = Manifold(4, 'M', latex_name=r'\mathcal{M}', structure='topological')
sage: M
4-dimensional topological manifold M
sage: latex(M)
\mathcal{M}
sage: type(M)
<class 'sage.manifolds.manifold.TopologicalManifold_with_category'>
sage: M.base_field()
Real Field with 53 bits of precision
sage: dim(M)
4

The input parameter start_index defines the range of indices on the manifold:

sage: M = Manifold(4, 'M', structure='topological')
sage: list(M.irange())
[0, 1, 2, 3]
sage: M = Manifold(4, 'M', structure='topological', start_index=1)
sage: list(M.irange())
[1, 2, 3, 4]
sage: list(Manifold(4, 'M', structure='topological', start_index=-2).irange())
[-2, -1, 0, 1]

A complex manifold:

sage: N = Manifold(3, 'N', structure='topological', field='complex'); N
Complex 3-dimensional topological manifold N

A manifold over \(\QQ\):

sage: N = Manifold(6, 'N', structure='topological', field=QQ); N
6-dimensional topological manifold N over the Rational Field

A manifold over \(\QQ_5\), the field of 5-adic numbers:

sage: N = Manifold(2, 'N', structure='topological', field=Qp(5)); N
2-dimensional topological manifold N over the 5-adic Field with capped
 relative precision 20

A manifold is a Sage parent object, in the category of topological manifolds over a given topological field (see Manifolds):

sage: isinstance(M, Parent)
True
sage: M.category()
Category of manifolds over Real Field with 53 bits of precision
sage: from sage.categories.manifolds import Manifolds
sage: M.category() is Manifolds(RR)
True
sage: M.category() is Manifolds(M.base_field())
True
sage: M in Manifolds(RR)
True
sage: N in Manifolds(Qp(5))
True

The corresponding Sage elements are points:

sage: X.<t, x, y, z> = M.chart()
sage: p = M.an_element(); p
Point on the 4-dimensional topological manifold M
sage: p.parent()
4-dimensional topological manifold M
sage: M.is_parent_of(p)
True
sage: p in M
True

The manifold’s points are instances of class ManifoldPoint:

sage: isinstance(p, sage.manifolds.point.ManifoldPoint)
True

Since an open subset of a topological manifold \(M\) is itself a topological manifold, open subsets of \(M\) are instances of the class TopologicalManifold:

sage: U = M.open_subset('U'); U
Open subset U of the 4-dimensional topological manifold M
sage: isinstance(U, sage.manifolds.manifold.TopologicalManifold)
True
sage: U.base_field() == M.base_field()
True
sage: dim(U) == dim(M)
True
sage: U.category()
Join of Category of subobjects of sets and Category of manifolds over
 Real Field with 53 bits of precision

The manifold passes all the tests of the test suite relative to its category:

sage: TestSuite(M).run()
atlas()

Return the list of charts that have been defined on the manifold.

EXAMPLES:

Let us consider \(\RR^2\) as a 2-dimensional manifold:

sage: M = Manifold(2, 'R^2', structure='topological')

Immediately after the manifold creation, the atlas is empty, since no chart has been defined yet:

sage: M.atlas()
[]

Let us introduce the chart of Cartesian coordinates:

sage: c_cart.<x,y> = M.chart()
sage: M.atlas()
[Chart (R^2, (x, y))]

The complement of the half line \(\{y = 0, x \geq 0\}\):

sage: U = M.open_subset('U', coord_def={c_cart: (y!=0,x<0)})
sage: U.atlas()
[Chart (U, (x, y))]
sage: M.atlas()
[Chart (R^2, (x, y)), Chart (U, (x, y))]

Spherical (polar) coordinates on U:

sage: c_spher.<r, ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi')
sage: U.atlas()
[Chart (U, (x, y)), Chart (U, (r, ph))]
sage: M.atlas()
[Chart (R^2, (x, y)), Chart (U, (x, y)), Chart (U, (r, ph))]

See also

top_charts()

base_field()

Return the field on which the manifold is defined.

OUTPUT:

  • a topological field

EXAMPLES:

sage: M = Manifold(3, 'M', structure='topological')
sage: M.base_field()
Real Field with 53 bits of precision
sage: M = Manifold(3, 'M', structure='topological', field='complex')
sage: M.base_field()
Complex Field with 53 bits of precision
sage: M = Manifold(3, 'M', structure='topological', field=QQ)
sage: M.base_field()
Rational Field
base_field_type()

Return the type of topological field on which the manifold is defined.

OUTPUT:

  • a string describing the field, with three possible values:

    • 'real' for the real field \(\RR\)

    • 'complex' for the complex field \(\CC\)

    • 'neither_real_nor_complex' for a field different from \(\RR\) and \(\CC\)

EXAMPLES:

sage: M = Manifold(3, 'M', structure='topological')
sage: M.base_field_type()
'real'
sage: M = Manifold(3, 'M', structure='topological', field='complex')
sage: M.base_field_type()
'complex'
sage: M = Manifold(3, 'M', structure='topological', field=QQ)
sage: M.base_field_type()
'neither_real_nor_complex'
chart(coordinates='', names=None, calc_method=None, coord_restrictions=None)

Define a chart, the domain of which is the manifold.

A chart is a pair \((U, \varphi)\), where \(U\) is the current manifold and \(\varphi: U \rightarrow V \subset K^n\) is a homeomorphism from \(U\) to an open subset \(V\) of \(K^n\), \(K\) being the field on which the manifold is defined.

The components \((x^1, \ldots, x^n)\) of \(\varphi\), defined by \(\varphi(p) = (x^1(p), \ldots, x^n(p)) \in K^n\) for any point \(p \in U\), are called the coordinates of the chart \((U, \varphi)\).

See Chart for a complete documentation.

INPUT:

  • coordinates – (default: '' (empty string)) string defining the coordinate symbols, ranges and possible periodicities, see below

  • names – (default: None) unused argument, except if coordinates is not provided; it must then be a tuple containing the coordinate symbols (this is guaranteed if the shortcut operator <,> is used)

  • calc_method – (default: None) string defining the calculus method to be used on this chart; must be one of

    • 'SR': Sage’s default symbolic engine (Symbolic Ring)

    • 'sympy': SymPy

    • None: the current calculus method defined on the manifold is used (cf. set_calculus_method())

  • coord_restrictions: Additional restrictions on the coordinates. See below.

The coordinates declared in the string coordinates are separated by ' ' (whitespace) and each coordinate has at most four fields, separated by a colon (':'):

  1. The coordinate symbol (a letter or a few letters).

  2. (optional, only for manifolds over \(\RR\)) The interval \(I\) defining the coordinate range: if not provided, the coordinate is assumed to span all \(\RR\); otherwise \(I\) must be provided in the form (a,b) (or equivalently ]a,b[) The bounds a and b can be +/-Infinity, Inf, infinity, inf or oo. For singular coordinates, non-open intervals such as [a,b] and (a,b] (or equivalently ]a,b]) are allowed. Note that the interval declaration must not contain any space character.

  3. (optional) Indicator of the periodic character of the coordinate, either as period=T, where T is the period, or, for manifolds over \(\RR\) only, as the keyword periodic (the value of the period is then deduced from the interval \(I\) declared in field 2; see the example below)

  4. (optional) The LaTeX spelling of the coordinate; if not provided the coordinate symbol given in the first field will be used.

The order of fields 2 to 4 does not matter and each of them can be omitted. If it contains any LaTeX expression, the string coordinates must be declared with the prefix ‘r’ (for “raw”) to allow for a proper treatment of the backslash character (see examples below). If no interval range, no period and no LaTeX spelling is to be set for any coordinate, the argument coordinates can be omitted when the shortcut operator <,> is used to declare the chart (see examples below).

Additional restrictions on the coordinates can be set using the argument coord_restrictions.

A restriction can be any symbolic equality or inequality involving the coordinates, such as x > y or x^2 + y^2 != 0. The items of the list (or set or frozenset) coord_restrictions are combined with the and operator; if some restrictions are to be combined with the or operator instead, they have to be passed as a tuple in some single item of the list (or set or frozenset) coord_restrictions. For example:

coord_restrictions=[x > y, (x != 0, y != 0), z^2 < x]

means (x > y) and ((x != 0) or (y != 0)) and (z^2 < x). If the list coord_restrictions contains only one item, this item can be passed as such, i.e. writing x > y instead of the single element list [x > y]. If the chart variables have not been declared as variables yet, coord_restrictions must be lambda-quoted.

OUTPUT:

  • the created chart, as an instance of Chart or one of its subclasses, like RealDiffChart for differentiable manifolds over \(\RR\).

EXAMPLES:

Chart on a 2-dimensional manifold:

sage: M = Manifold(2, 'M', structure='topological')
sage: X = M.chart('x y'); X
Chart (M, (x, y))
sage: X[0]
x
sage: X[1]
y
sage: X[:]
(x, y)

The declared coordinates are not known at the global level:

sage: y
Traceback (most recent call last):
...
NameError: name 'y' is not defined

They can be recovered by the operator [:] applied to the chart:

sage: (x, y) = X[:]
sage: y
y
sage: type(y)
<type 'sage.symbolic.expression.Expression'>

But a shorter way to proceed is to use the operator <,> in the left-hand side of the chart declaration (there is then no need to pass the string ‘x y’ to chart()):

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart(); X
Chart (M, (x, y))

Indeed, the declared coordinates are then known at the global level:

sage: y
y
sage: (x,y) == X[:]
True

Actually the instruction X.<x,y> = M.chart() is equivalent to the combination of the two instructions X = M.chart('x y') and (x,y) = X[:].

As an example of coordinate ranges and LaTeX symbols passed via the string coordinates to chart(), let us introduce polar coordinates:

sage: U = M.open_subset('U', coord_def={X: x^2+y^2 != 0})
sage: P.<r,ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):periodic:\phi'); P
Chart (U, (r, ph))
sage: P.coord_range()
r: (0, +oo); ph: [0, 2*pi] (periodic)
sage: latex(P)
\left(U,(r, {\phi})\right)

Using coord_restrictions:

sage: D = Manifold(2, 'D', structure='topological')
sage: X.<x,y> = D.chart(coord_restrictions=lambda x,y: [x^2+y^2<1, x>0]); X
Chart (D, (x, y))
sage: X.valid_coordinates(0, 0)
False
sage: X.valid_coordinates(1/2, 0)
True

See the documentation of classes Chart and RealChart for more examples, especially regarding the coordinates ranges and restrictions.

constant_scalar_field(value, name=None, latex_name=None)

Define a constant scalar field on the manifold.

INPUT:

  • value – constant value of the scalar field, either a numerical value or a symbolic expression not involving any chart coordinates

  • name – (default: None) name given to the scalar field

  • latex_name – (default: None) LaTeX symbol to denote the scalar field; if None, the LaTeX symbol is set to name

OUTPUT:

  • instance of ScalarField representing the scalar field whose constant value is value

EXAMPLES:

A constant scalar field 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: f = M.constant_scalar_field(-1) ; f
Scalar field on the 2-dimensional topological manifold M
sage: f.display()
M → ℝ
on U: (x, y) ↦ -1
on V: (u, v) ↦ -1

We have:

sage: f.restrict(U) == U.constant_scalar_field(-1)
True
sage: M.constant_scalar_field(0) is M.zero_scalar_field()
True
continuous_map(codomain, coord_functions=None, chart1=None, chart2=None, name=None, latex_name=None)

Define a continuous map from self to codomain.

INPUT:

  • codomainTopologicalManifold; the map’s codomain

  • coord_functions – (default: None) if not None, must be either

    • (i) a dictionary of the coordinate expressions (as lists (or tuples) of the coordinates of the image expressed in terms of the coordinates of the considered point) with the pairs of charts (chart1, chart2) as keys (chart1 being a chart on self and chart2 a chart on codomain);

    • (ii) a single coordinate expression in a given pair of charts, the latter being provided by the arguments chart1 and chart2;

    in both cases, if the dimension of the codomain is \(1\), a single coordinate expression can be passed instead of a tuple with a single element

  • chart1 – (default: None; used only in case (ii) above) chart on self defining the start coordinates involved in coord_functions for case (ii); if None, the coordinates are assumed to refer to the default chart of self

  • chart2 – (default: None; used only in case (ii) above) chart on codomain defining the target coordinates involved in coord_functions for case (ii); if None, the coordinates are assumed to refer to the default chart of codomain

  • name – (default: None) name given to the continuous map

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

OUTPUT:

EXAMPLES:

A continuous map between an open subset of \(S^2\) covered by regular spherical coordinates and \(\RR^3\):

sage: M = Manifold(2, 'S^2', structure='topological')
sage: U = M.open_subset('U')
sage: c_spher.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
sage: N = Manifold(3, 'R^3', latex_name=r'\RR^3', structure='topological')
sage: c_cart.<x,y,z> = N.chart()  # Cartesian coord. on R^3
sage: Phi = U.continuous_map(N, (sin(th)*cos(ph), sin(th)*sin(ph), cos(th)),
....:                        name='Phi', latex_name=r'\Phi')
sage: Phi
Continuous map Phi from the Open subset U of the 2-dimensional topological manifold S^2 to the 3-dimensional topological manifold R^3

The same definition, but with a dictionary with pairs of charts as keys (case (i) above):

sage: Phi1 = U.continuous_map(N,
....:        {(c_spher, c_cart): (sin(th)*cos(ph), sin(th)*sin(ph), cos(th))},
....:        name='Phi', latex_name=r'\Phi')
sage: Phi1 == Phi
True

The continuous map acting on a point:

sage: p = U.point((pi/2, pi)) ; p
Point on the 2-dimensional topological manifold S^2
sage: Phi(p)
Point on the 3-dimensional topological manifold R^3
sage: Phi(p).coord(c_cart)
(-1, 0, 0)
sage: Phi1(p) == Phi(p)
True

See also

See ContinuousMap for the complete documentation and more examples.

Todo

Allow the construction of continuous maps from self to the base field (considered as a trivial 1-dimensional manifold).

coord_change(chart1, chart2)

Return the change of coordinates (transition map) between two charts defined on the manifold.

The change of coordinates must have been defined previously, for instance by the method transition_map().

INPUT:

  • chart1 – chart 1

  • chart2 – chart 2

OUTPUT:

  • instance of CoordChange representing the transition map from chart 1 to chart 2

EXAMPLES:

Change of coordinates on a 2-dimensional manifold:

sage: M = Manifold(2, 'M', structure='topological')
sage: c_xy.<x,y> = M.chart()
sage: c_uv.<u,v> = M.chart()
sage: c_xy.transition_map(c_uv, (x+y, x-y)) # defines the coord. change
Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v))
sage: M.coord_change(c_xy, c_uv) # returns the coord. change defined above
Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v))
coord_changes()

Return the changes of coordinates (transition maps) defined on subsets of the manifold.

OUTPUT:

  • dictionary of changes of coordinates, with pairs of charts as keys

EXAMPLES:

Various changes of coordinates on a 2-dimensional manifold:

sage: M = Manifold(2, 'M', structure='topological')
sage: c_xy.<x,y> = M.chart()
sage: c_uv.<u,v> = M.chart()
sage: xy_to_uv = c_xy.transition_map(c_uv, [x+y, x-y])
sage: M.coord_changes()
{(Chart (M, (x, y)),
  Chart (M, (u, v))): Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v))}
sage: uv_to_xy = xy_to_uv.inverse()
sage: M.coord_changes()  # random (dictionary output)
{(Chart (M, (u, v)),
  Chart (M, (x, y))): Change of coordinates from Chart (M, (u, v)) to Chart (M, (x, y)),
 (Chart (M, (x, y)),
  Chart (M, (u, v))): Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v))}
sage: c_rs.<r,s> = M.chart()
sage: uv_to_rs = c_uv.transition_map(c_rs, [-u+2*v, 3*u-v])
sage: M.coord_changes()  # random (dictionary output)
{(Chart (M, (u, v)),
  Chart (M, (r, s))): Change of coordinates from Chart (M, (u, v)) to Chart (M, (r, s)),
 (Chart (M, (u, v)),
  Chart (M, (x, y))): Change of coordinates from Chart (M, (u, v)) to Chart (M, (x, y)),
 (Chart (M, (x, y)),
  Chart (M, (u, v))): Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v))}
sage: xy_to_rs = uv_to_rs * xy_to_uv
sage: M.coord_changes()  # random (dictionary output)
{(Chart (M, (u, v)),
  Chart (M, (r, s))): Change of coordinates from Chart (M, (u, v)) to Chart (M, (r, s)),
 (Chart (M, (u, v)),
  Chart (M, (x, y))): Change of coordinates from Chart (M, (u, v)) to Chart (M, (x, y)),
 (Chart (M, (x, y)),
  Chart (M, (u, v))): Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v)),
 (Chart (M, (x, y)),
  Chart (M, (r, s))): Change of coordinates from Chart (M, (x, y)) to Chart (M, (r, s))}
default_chart()

Return the default chart defined on the manifold.

Unless changed via set_default_chart(), the default chart is the first one defined on a subset of the manifold (possibly itself).

OUTPUT:

  • instance of Chart representing the default chart

EXAMPLES:

Default chart on a 2-dimensional manifold and on some subsets:

sage: M = Manifold(2, 'M', structure='topological')
sage: M.chart('x y')
Chart (M, (x, y))
sage: M.chart('u v')
Chart (M, (u, v))
sage: M.default_chart()
Chart (M, (x, y))
sage: A = M.open_subset('A')
sage: A.chart('t z')
Chart (A, (t, z))
sage: A.default_chart()
Chart (A, (t, z))
dim()

Return the dimension of the manifold over its base field.

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: M.dimension()
2

A shortcut is dim():

sage: M.dim()
2

The Sage global function dim can also be used:

sage: dim(M)
2
dimension()

Return the dimension of the manifold over its base field.

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: M.dimension()
2

A shortcut is dim():

sage: M.dim()
2

The Sage global function dim can also be used:

sage: dim(M)
2
get_chart(coordinates, domain=None)

Get a chart from its coordinates.

The chart must have been previously created by the method chart().

INPUT:

  • coordinates – single string composed of the coordinate symbols separated by a space

  • domain – (default: None) string containing the name of the chart’s domain, which must be a subset of the current manifold; if None, the current manifold is assumed

OUTPUT:

  • instance of Chart (or of the subclass RealChart) representing the chart corresponding to the above specifications

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: M.get_chart('x y')
Chart (M, (x, y))
sage: M.get_chart('x y') is X
True
sage: U = M.open_subset('U', coord_def={X: (y!=0,x<0)})
sage: Y.<r, ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi')
sage: M.atlas()
[Chart (M, (x, y)), Chart (U, (x, y)), Chart (U, (r, ph))]
sage: M.get_chart('x y', domain='U')
Chart (U, (x, y))
sage: M.get_chart('x y', domain='U') is X.restrict(U)
True
sage: U.get_chart('r ph')
Chart (U, (r, ph))
sage: M.get_chart('r ph', domain='U')
Chart (U, (r, ph))
sage: M.get_chart('r ph', domain='U') is Y
True
has_orientation()

Check whether self admits an obvious or by user set orientation.

See also

Consult orientation() for details about orientations.

Note

Notice that if has_orientation() returns False this does not necessarily mean that the manifold admits no orientation. It just means that the user has to set an orientation manually in that case, see set_orientation().

EXAMPLES:

The trivial case:

sage: M = Manifold(3, 'M', structure='top')
sage: c.<x,y,z> = M.chart()
sage: M.has_orientation()
True

The non-trivial case:

sage: M = Manifold(2, 'M', structure='top')
sage: U = M.open_subset('U'); V = M.open_subset('V')
sage: M.declare_union(U, V)
sage: c_xy.<x,y> = U.chart(); c_uv.<u,v> = V.chart()
sage: M.has_orientation()
False
sage: M.set_orientation([c_xy, c_uv])
sage: M.has_orientation()
True
homeomorphism(codomain, coord_functions=None, chart1=None, chart2=None, name=None, latex_name=None)

Define a homeomorphism between the current manifold and another one.

See ContinuousMap for a complete documentation.

INPUT:

  • codomainTopologicalManifold; codomain of the homeomorphism

  • coord_functions – (default: None) if not None, must be either

    • (i) a dictionary of the coordinate expressions (as lists (or tuples) of the coordinates of the image expressed in terms of the coordinates of the considered point) with the pairs of charts (chart1, chart2) as keys (chart1 being a chart on self and chart2 a chart on codomain);

    • (ii) a single coordinate expression in a given pair of charts, the latter being provided by the arguments chart1 and chart2;

    in both cases, if the dimension of the codomain is \(1\), a single coordinate expression can be passed instead of a tuple with a single element

  • chart1 – (default: None; used only in case (ii) above) chart on self defining the start coordinates involved in coord_functions for case (ii); if None, the coordinates are assumed to refer to the default chart of self

  • chart2 – (default: None; used only in case (ii) above) chart on codomain defining the target coordinates involved in coord_functions for case (ii); if None, the coordinates are assumed to refer to the default chart of codomain

  • name – (default: None) name given to the homeomorphism

  • latex_name – (default: None) LaTeX symbol to denote the homeomorphism; if None, the LaTeX symbol is set to name

OUTPUT:

EXAMPLES:

Homeomorphism between the open unit disk in \(\RR^2\) and \(\RR^2\):

sage: forget()  # for doctests only
sage: M = Manifold(2, 'M', structure='topological')  # the open unit disk
sage: c_xy.<x,y> = M.chart('x:(-1,1) y:(-1,1)', coord_restrictions=lambda x,y: x^2+y^2<1)
....:    # Cartesian coord on M
sage: N = Manifold(2, 'N', structure='topological')  # R^2
sage: c_XY.<X,Y> = N.chart()  # canonical coordinates on R^2
sage: Phi = M.homeomorphism(N, [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 2-dimensional topological manifold M to
 the 2-dimensional topological manifold N
sage: Phi.display()
Phi: M → N
   (x, y) ↦ (X, Y) = (x/sqrt(-x^2 - y^2 + 1), y/sqrt(-x^2 - y^2 + 1))

The inverse homeomorphism:

sage: Phi^(-1)
Homeomorphism Phi^(-1) from the 2-dimensional topological
 manifold N to the 2-dimensional topological manifold M
sage: (Phi^(-1)).display()
Phi^(-1): N → M
   (X, Y) ↦ (x, y) = (X/sqrt(X^2 + Y^2 + 1), Y/sqrt(X^2 + Y^2 + 1))

See the documentation of ContinuousMap for more examples.

identity_map()

Identity map of self.

The identity map of a topological manifold \(M\) is the trivial homeomorphism:

\[\begin{split}\begin{array}{cccc} \mathrm{Id}_M: & M & \longrightarrow & M \\ & p & \longmapsto & p \end{array}\end{split}\]

OUTPUT:

EXAMPLES:

Identity map of a complex manifold:

sage: M = Manifold(2, 'M', structure='topological', field='complex')
sage: X.<x,y> = M.chart()
sage: id = M.identity_map(); id
Identity map Id_M of the Complex 2-dimensional topological manifold M
sage: id.parent()
Set of Morphisms from Complex 2-dimensional topological manifold M
 to Complex 2-dimensional topological manifold M in Category of
 manifolds over Complex Field with 53 bits of precision
sage: id.display()
Id_M: M → M
   (x, y) ↦ (x, y)

The identity map acting on a point:

sage: p = M((1+I, 3-I), name='p'); p
Point p on the Complex 2-dimensional topological manifold M
sage: id(p)
Point p on the Complex 2-dimensional topological manifold M
sage: id(p) == p
True

See also

See ContinuousMap for the complete documentation.

index_generator(nb_indices)

Generator of index series.

INPUT:

  • nb_indices – number of indices in a series

OUTPUT:

  • an iterable index series for a generic component with the specified number of indices

EXAMPLES:

Indices on a 2-dimensional manifold:

sage: M = Manifold(2, 'M', structure='topological', start_index=1)
sage: list(M.index_generator(2))
[(1, 1), (1, 2), (2, 1), (2, 2)]

Loops can be nested:

sage: for ind1 in M.index_generator(2):
....:     print("{} : {}".format(ind1, list(M.index_generator(2))))
(1, 1) : [(1, 1), (1, 2), (2, 1), (2, 2)]
(1, 2) : [(1, 1), (1, 2), (2, 1), (2, 2)]
(2, 1) : [(1, 1), (1, 2), (2, 1), (2, 2)]
(2, 2) : [(1, 1), (1, 2), (2, 1), (2, 2)]
irange(start=None)

Single index generator.

INPUT:

  • start – (default: None) initial value \(i_0\) of the index; if none are provided, the value returned by start_index() is assumed

OUTPUT:

  • an iterable index, starting from \(i_0\) and ending at \(i_0 + n - 1\), where \(n\) is the manifold’s dimension

EXAMPLES:

Index range on a 4-dimensional manifold:

sage: M = Manifold(4, 'M', structure='topological')
sage: list(M.irange())
[0, 1, 2, 3]
sage: list(M.irange(2))
[2, 3]

Index range on a 4-dimensional manifold with starting index=1:

sage: M = Manifold(4, 'M', structure='topological', start_index=1)
sage: list(M.irange())
[1, 2, 3, 4]
sage: list(M.irange(2))
[2, 3, 4]

In general, one has always:

sage: next(M.irange()) == M.start_index()
True
is_manifestly_coordinate_domain()

Return True if the manifold is known to be the domain of some coordinate chart and False otherwise.

If False is returned, either the manifold cannot be the domain of some coordinate chart or no such chart has been declared yet.

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: U = M.open_subset('U')
sage: X.<x,y> = U.chart()
sage: U.is_manifestly_coordinate_domain()
True
sage: M.is_manifestly_coordinate_domain()
False
sage: Y.<u,v> = M.chart()
sage: M.is_manifestly_coordinate_domain()
True
is_open()

Return if self is an open set.

In the present case (manifold or open subset of it), always return True.

one_scalar_field()

Return the constant scalar field with value the unit element of the base field of self.

OUTPUT:

  • a ScalarField representing the constant scalar field with value the unit element of the base field of self

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.one_scalar_field(); f
Scalar field 1 on the 2-dimensional topological manifold M
sage: f.display()
1: M → ℝ
   (x, y) ↦ 1
sage: f.parent()
Algebra of scalar fields on the 2-dimensional topological manifold M
sage: f is M.scalar_field_algebra().one()
True
open_subset(name, latex_name=None, coord_def={}, supersets=None)

Create an open subset of the manifold.

An open subset is a set that is (i) included in the manifold and (ii) open with respect to the manifold’s topology. It is a topological manifold by itself. Hence the returned object is an instance of TopologicalManifold.

INPUT:

  • name – name given to the open subset

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

  • coord_def – (default: {}) definition of the subset in terms of coordinates; coord_def must a be dictionary with keys charts on the manifold and values the symbolic expressions formed by the coordinates to define the subset

  • supersets – (default: only self) list of sets that the new open subset is a subset of

OUTPUT:

EXAMPLES:

Creating an open subset of a 2-dimensional manifold:

sage: M = Manifold(2, 'M', structure='topological')
sage: A = M.open_subset('A'); A
Open subset A of the 2-dimensional topological manifold M

As an open subset of a topological manifold, A is itself a topological manifold, on the same topological field and of the same dimension as M:

sage: isinstance(A, sage.manifolds.manifold.TopologicalManifold)
True
sage: A.base_field() == M.base_field()
True
sage: dim(A) == dim(M)
True
sage: A.category() is M.category().Subobjects()
True

Creating an open subset of A:

sage: B = A.open_subset('B'); B
Open subset B of the 2-dimensional topological manifold M

We have then:

sage: frozenset(A.subsets())  # random (set output)
{Open subset B of the 2-dimensional topological manifold M,
 Open subset A of the 2-dimensional topological manifold M}
sage: B.is_subset(A)
True
sage: B.is_subset(M)
True

Defining an open subset by some coordinate restrictions: the open unit disk in \(\RR^2\):

sage: M = Manifold(2, 'R^2', structure='topological')
sage: c_cart.<x,y> = M.chart() # Cartesian coordinates on R^2
sage: U = M.open_subset('U', coord_def={c_cart: x^2+y^2<1}); U
Open subset U of the 2-dimensional topological manifold R^2

Since the argument coord_def has been set, U is automatically provided with a chart, which is the restriction of the Cartesian one to U:

sage: U.atlas()
[Chart (U, (x, y))]

Therefore, one can immediately check whether a point belongs to U:

sage: M.point((0,0)) in U
True
sage: M.point((1/2,1/3)) in U
True
sage: M.point((1,2)) in U
False
options(*get_value, **set_value)

Sets and displays the options for manifolds. If no parameters are set, then the function returns a copy of the options dictionary.

The options to manifolds can be accessed as the method Manifold.options.

OPTIONS:

  • omit_function_arguments – (default: False) Determine whether the arguments of symbolic functions are printed

  • textbook_output – (default: True) textbook-like output instead of the Pynac output for derivatives

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: g = function('g')(x, y)

For coordinate functions, the display is more “textbook” like:

sage: f = X.function(diff(g, x) + diff(g, y))
sage: f
d(g)/dx + d(g)/dy
sage: latex(f)
\frac{\partial\,g}{\partial x} + \frac{\partial\,g}{\partial y}

One can switch to Pynac notation by changing textbook_output to False:

sage: Manifold.options.textbook_output=False
sage: f
diff(g(x, y), x) + diff(g(x, y), y)
sage: latex(f)
\frac{\partial}{\partial x}g\left(x, y\right)
 + \frac{\partial}{\partial y}g\left(x, y\right)
sage: Manifold.options._reset()

If there is a clear understanding that \(u\) and \(v\) are functions of \((x,y)\), the explicit mention of the latter can be cumbersome in lengthy tensor expressions:

sage: f = X.function(function('u')(x, y) * function('v')(x, y))
sage: f
u(x, y)*v(x, y)

We can switch it off by:

sage: M.options.omit_function_arguments=True
sage: f
u*v
sage: M.options._reset()

See GlobalOptions for more features of these options.

orientation()

Get the preferred orientation of self if available.

An orientation of an \(n\)-dimensional topologial manifold is an atlas of charts whose transition maps are orientation preserving. A homeomorphism \(f \colon U \to V\) for open subsets \(U, V \subset \RR^n\) is called orientation preserving if for each \(x \in U\) the following map between singular homologies is the identity:

\[H_n(\RR^n, \RR^n - 0; \ZZ) \cong H_n(U, U - x; \ZZ) \xrightarrow{f_*} H_n(V, V - f(x)) \cong H_n(\RR^n, \RR^n - 0; \ZZ)\]

See this link for details.

Note

Notice that for differentiable manifolds, the notion of orientability does not need homology theory at all. See orientation() for details

The trivial case corresponds to the manifold being covered by one chart. In that case, if no preferred orientation has been manually set before, one of those charts (usually the default chart) is set to the preferred orientation and returned here.

EXAMPLES:

If the manifold is covered by only one chart, it certainly admits an orientation:

sage: M = Manifold(3, 'M', structure='top')
sage: c.<x,y,z> = M.chart()
sage: M.orientation()
[Chart (M, (x, y, z))]

Usually, an orientation cannot be obtained so easily:

sage: M = Manifold(2, 'M', structure='top')
sage: U = M.open_subset('U'); V = M.open_subset('V')
sage: M.declare_union(U, V)
sage: c_xy.<x,y> = U.chart(); c_uv.<u,v> = V.chart()
sage: M.orientation()
[]

In that case, the orientation can be set by the user manually:

sage: M.set_orientation([c_xy, c_uv])
sage: M.orientation()
[Chart (U, (x, y)), Chart (V, (u, v))]

The orientation on submanifolds are inherited from the ambient manifold:

sage: W = U.intersection(V, name='W')
sage: W.orientation()
[Chart (W, (x, y))]
scalar_field(coord_expression=None, chart=None, name=None, latex_name=None)

Define a scalar field on the manifold.

See ScalarField (or DiffScalarField if the manifold is differentiable) for a complete documentation.

INPUT:

  • coord_expression – (default: None) coordinate expression(s) of the scalar field; this can be either

    • a single coordinate expression; if the argument chart is 'all', this expression is set to all the charts defined on the open set; otherwise, the expression is set in the specific chart provided by the argument chart

    • a dictionary of coordinate expressions, with the charts as keys

  • chart – (default: None) chart defining the coordinates used in coord_expression when the latter is a single coordinate expression; if None, the default chart of the open set is assumed; if chart=='all', coord_expression is assumed to be independent of the chart (constant scalar field)

  • name – (default: None) name given to the scalar field

  • latex_name – (default: None) LaTeX symbol to denote the scalar field; if None, the LaTeX symbol is set to name

If coord_expression is None or does not fully specified the scalar field, other coordinate expressions can be added subsequently by means of the methods add_expr(), add_expr_by_continuation(), or set_expr()

OUTPUT:

  • instance of ScalarField (or of the subclass DiffScalarField if the manifold is differentiable) representing the defined scalar field

EXAMPLES:

A scalar field defined by its coordinate expression in the open set’s default chart:

sage: M = Manifold(3, 'M', structure='topological')
sage: U = M.open_subset('U')
sage: c_xyz.<x,y,z> = U.chart()
sage: f = U.scalar_field(sin(x)*cos(y) + z, name='F'); f
Scalar field F on the Open subset U of the 3-dimensional topological manifold M
sage: f.display()
F: U → ℝ
   (x, y, z) ↦ cos(y)*sin(x) + z
sage: f.parent()
Algebra of scalar fields on the Open subset U of the 3-dimensional topological manifold M
sage: f in U.scalar_field_algebra()
True

Equivalent definition with the chart specified:

sage: f = U.scalar_field(sin(x)*cos(y) + z, chart=c_xyz, name='F')
sage: f.display()
F: U → ℝ
   (x, y, z) ↦ cos(y)*sin(x) + z

Equivalent definition with a dictionary of coordinate expression(s):

sage: f = U.scalar_field({c_xyz: sin(x)*cos(y) + z}, name='F')
sage: f.display()
F: U → ℝ
   (x, y, z) ↦ cos(y)*sin(x) + z

See the documentation of class ScalarField for more examples.

scalar_field_algebra()

Return the algebra of scalar fields defined the manifold.

See ScalarFieldAlgebra for a complete documentation.

OUTPUT:

  • instance of ScalarFieldAlgebra representing the algebra \(C^0(U)\) of all scalar fields defined on \(U\) = self

EXAMPLES:

Scalar algebra of a 3-dimensional open subset:

sage: M = Manifold(3, 'M', structure='topological')
sage: U = M.open_subset('U')
sage: CU = U.scalar_field_algebra() ; CU
Algebra of scalar fields on the Open subset U of the 3-dimensional topological manifold M
sage: CU.category()
Join of Category of commutative algebras over Symbolic Ring and Category of homsets of topological spaces
sage: CU.zero()
Scalar field zero on the Open subset U of the 3-dimensional topological manifold M

The output is cached:

sage: U.scalar_field_algebra() is CU
True
set_calculus_method(method)

Set the calculus method to be used for coordinate computations on this manifold.

The provided method is transmitted to all coordinate charts defined on the manifold.

INPUT:

  • method – string specifying the method to be used for coordinate computations on this manifold; one of

    • 'SR': Sage’s default symbolic engine (Symbolic Ring)

    • 'sympy': SymPy

EXAMPLES:

Let us consider a scalar field f on a 2-dimensional manifold:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field(x^2 + cos(y)*sin(x), name='F')

By default, the coordinate expression of f returned by expr() is a Sage’s symbolic expression:

sage: f.expr()
x^2 + cos(y)*sin(x)
sage: type(f.expr())
<type 'sage.symbolic.expression.Expression'>
sage: parent(f.expr())
Symbolic Ring
sage: f.display()
F: M → ℝ
   (x, y) ↦ x^2 + cos(y)*sin(x)

If we change the calculus method to SymPy, it becomes a SymPy object instead:

sage: M.set_calculus_method('sympy')
sage: f.expr()
x**2 + sin(x)*cos(y)
sage: type(f.expr())
<class 'sympy.core.add.Add'>
sage: parent(f.expr())
<class 'sympy.core.add.Add'>
sage: f.display()
F: M → ℝ
   (x, y) ↦ x**2 + sin(x)*cos(y)

Back to the Symbolic Ring:

sage: M.set_calculus_method('SR')
sage: f.display()
F: M → ℝ
   (x, y) ↦ x^2 + cos(y)*sin(x)

The calculus method chosen via set_calculus_method() applies to any chart defined subsequently on the manifold:

sage: M.set_calculus_method('sympy')
sage: Y.<u,v> = M.chart()  # a new chart
sage: Y.calculus_method()
Available calculus methods (* = current):
 - SR (default)
 - sympy (*)

See also

calculus_method() for a control of the calculus method chart by chart

set_default_chart(chart)

Changing the default chart on self.

INPUT:

  • chart – a chart (must be defined on some subset self)

EXAMPLES:

Charts on a 2-dimensional manifold:

sage: M = Manifold(2, 'M', structure='topological')
sage: c_xy.<x,y> = M.chart()
sage: c_uv.<u,v> = M.chart()
sage: M.default_chart()
Chart (M, (x, y))
sage: M.set_default_chart(c_uv)
sage: M.default_chart()
Chart (M, (u, v))
set_orientation(orientation)

Set the preferred orientation of self.

INPUT:

  • orientation – a chart or a list of charts

Warning

It is the user’s responsibility that the orientation set here is indeed an orientation. There is no check going on in the background. See orientation() for the definition of an orientation.

EXAMPLES:

Set an orientation on a manifold:

sage: M = Manifold(2, 'M', structure='top')
sage: c_xy.<x,y> = M.chart(); c_uv.<u,v> = M.chart()
sage: M.set_orientation(c_uv)
sage: M.orientation()
[Chart (M, (u, v))]

Set an orientation in the non-trivial case:

sage: M = Manifold(2, 'M', structure='top')
sage: U = M.open_subset('U'); V = M.open_subset('V')
sage: M.declare_union(U, V)
sage: c_xy.<x,y> = U.chart(); c_uv.<u,v> = V.chart()
sage: M.set_orientation([c_xy, c_uv])
sage: M.orientation()
[Chart (U, (x, y)), Chart (V, (u, v))]
set_simplify_function(simplifying_func, method=None)

Set the simplifying function associated to a given coordinate calculus method in all the charts defined on self.

INPUT:

  • simplifying_func – either the string 'default' for restoring the default simplifying function or a function f of a single argument expr such that f(expr) returns an object of the same type as expr (hopefully the simplified version of expr), this type being

    • Expression if method = 'SR'

    • a SymPy type if method = 'sympy'

  • method – (default: None) string defining the calculus method for which simplifying_func is provided; must be one of

    • 'SR': Sage’s default symbolic engine (Symbolic Ring)

    • 'sympy': SymPy

    • None: the currently active calculus method on each chart is assumed

See also

calculus_method() and sage.manifolds.calculus_method.CalculusMethod.simplify() for a control of the calculus method chart by chart

EXAMPLES:

Les us add two scalar fields on a 2-dimensional manifold:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field((x+y)^2 + cos(x)^2)
sage: g = M.scalar_field(-x^2-2*x*y-y^2 + sin(x)^2)
sage: f.expr()
(x + y)^2 + cos(x)^2
sage: g.expr()
-x^2 - 2*x*y - y^2 + sin(x)^2
sage: s = f + g

The outcome is automatically simplified:

sage: s.expr()
1

The simplification is performed thanks to the default simplifying function on chart X, which is simplify_chain_real() in the present case (real manifold and SR calculus):

sage: X.calculus_method().simplify_function() is \
....: sage.manifolds.utilities.simplify_chain_real
True

Let us change it to the generic Sage function simplify():

sage: M.set_simplify_function(simplify)
sage: X.calculus_method().simplify_function() is simplify
True

simplify() is faster, but it does not do much:

sage: s = f + g
sage: s.expr()
(x + y)^2 - x^2 - 2*x*y - y^2 + cos(x)^2 + sin(x)^2

We can replaced it by any user defined function, for instance:

sage: def simpl_trig(a):
....:     return a.simplify_trig()
sage: M.set_simplify_function(simpl_trig)
sage: s = f + g
sage: s.expr()
1

The default simplifying function is restored via:

sage: M.set_simplify_function('default')

Then we are back to:

sage: X.calculus_method().simplify_function() is \
....: sage.manifolds.utilities.simplify_chain_real
True

Thanks to the argument method, one can specify a simplifying function for a calculus method distinct from the current one. For instance, let us define a simplifying function for SymPy (note that trigsimp() is a SymPy method only):

sage: def simpl_trig_sympy(a):
....:     return a.trigsimp()
sage: M.set_simplify_function(simpl_trig_sympy, method='sympy')

Then, it becomes active as soon as we change the calculus engine to SymPy:

sage: M.set_calculus_method('sympy')
sage: X.calculus_method().simplify_function() is simpl_trig_sympy
True

We have then:

sage: s = f + g
sage: s.expr()
1
sage: type(s.expr())
<class 'sympy.core.numbers.One'>
start_index()

Return the first value of the index range used on the manifold.

This is the parameter start_index passed at the construction of the manifold.

OUTPUT:

  • the integer \(i_0\) such that all indices of indexed objects on the manifold range from \(i_0\) to \(i_0 + n - 1\), where \(n\) is the manifold’s dimension

EXAMPLES:

sage: M = Manifold(3, 'M', structure='topological')
sage: M.start_index()
0
sage: M = Manifold(3, 'M', structure='topological', start_index=1)
sage: M.start_index()
1
top_charts()

Return the list of charts defined on subsets of the current manifold that are not subcharts of charts on larger subsets.

OUTPUT:

  • list of charts defined on open subsets of the manifold but not on larger subsets

EXAMPLES:

Charts on a 2-dimensional manifold:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: U = M.open_subset('U', coord_def={X: x>0})
sage: Y.<u,v> = U.chart()
sage: M.top_charts()
[Chart (M, (x, y)), Chart (U, (u, v))]

Note that the (user) atlas contains one more chart: (U, (x,y)), which is not a “top” chart:

sage: M.atlas()
[Chart (M, (x, y)), Chart (U, (x, y)), Chart (U, (u, v))]

See also

atlas() for the complete list of charts defined on the manifold.

vector_bundle(rank, name, field='real', latex_name=None)

Return a topological vector bundle over the given field with given rank over this topological manifold.

INPUT:

  • rank – rank of the vector bundle

  • name – name given to the total space

  • field – (default: 'real') topological field giving the vector space structure to the fibers

  • latex_name – optional LaTeX name for the total space

OUTPUT:

EXAMPLES:

sage: M = Manifold(2, 'M', structure='top')
sage: M.vector_bundle(2, 'E')
Topological real vector bundle E -> M of rank 2 over the base space
 2-dimensional topological manifold M
zero_scalar_field()

Return the zero scalar field defined on self.

OUTPUT:

  • a ScalarField representing the constant scalar field with value \(0\)

EXAMPLES:

sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = M.zero_scalar_field() ; f
Scalar field zero on the 2-dimensional topological manifold M
sage: f.display()
zero: M → ℝ
   (x, y) ↦ 0
sage: f.parent()
Algebra of scalar fields on the 2-dimensional topological manifold M
sage: f is M.scalar_field_algebra().zero()
True