Topological Manifolds¶
Given a topological field \(K\) (in most applications, \(K = \RR\) or \(K = \CC\)) and a nonnegative 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
>>> from sage.all import *
>>> M = Manifold(Integer(2), 'S^2', structure='topological')
>>> M
2-dimensional topological manifold S^2
M = Manifold(2, 'S^2', structure='topological') M
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
>>> from sage.all import *
>>> M.base_field()
Real Field with 53 bits of precision
>>> dim(M)
2
M.base_field() dim(M)
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
>>> from sage.all import *
>>> U = M.open_subset('U'); U
Open subset U of the 2-dimensional topological manifold S^2
U = M.open_subset('U'); U
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))
>>> from sage.all import *
>>> stereoN = U.chart(names=('x', 'y',)); (x, y,) = stereoN._first_ngens(2); stereoN
Chart (U, (x, y))
stereoN.<x,y> = U.chart(); stereoN
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)
<class 'sage.symbolic.expression.Expression'>
>>> from sage.all import *
>>> y
y
>>> type(y)
<class 'sage.symbolic.expression.Expression'>
y type(y)
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
>>> from sage.all import *
>>> S = U.point((Integer(0),Integer(0)), chart=stereoN, name='S'); S
Point S on the 2-dimensional topological manifold S^2
S = U.point((0,0), chart=stereoN, name='S'); S
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))
>>> from sage.all import *
>>> V = M.open_subset('V'); V
Open subset V of the 2-dimensional topological manifold S^2
>>> stereoS = V.chart(names=('u', 'v',)); (u, v,) = stereoS._first_ngens(2); stereoS
Chart (V, (u, v))
V = M.open_subset('V'); V stereoS.<u,v> = V.chart(); stereoS
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
>>> from sage.all import *
>>> N = V.point((Integer(0),Integer(0)), chart=stereoS, name='N'); N
Point N on the 2-dimensional topological manifold S^2
N = V.point((0,0), chart=stereoS, name='N'); N
To fully construct the manifold, we declare that it is the union of \(U\) and \(V\):
sage: M.declare_union(U,V)
>>> from sage.all import *
>>> M.declare_union(U,V)
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)
>>> from sage.all import *
>>> stereoN_to_S = stereoN.transition_map(stereoS, [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))
>>> stereoN_to_S
Change of coordinates from Chart (W, (x, y)) to Chart (W, (u, v))
>>> stereoN_to_S.display()
u = x/(x^2 + y^2)
v = y/(x^2 + y^2)
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) stereoN_to_S stereoN_to_S.display()
We give the name W
to the Python variable representing \(W = U \cap V\):
sage: W = U.intersection(V)
>>> from sage.all import *
>>> W = U.intersection(V)
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)
>>> from sage.all import *
>>> stereoN_to_S.inverse()
Change of coordinates from Chart (W, (u, v)) to Chart (W, (x, y))
>>> stereoN_to_S.inverse().display()
x = u/(u^2 + v^2)
y = v/(u^2 + v^2)
stereoN_to_S.inverse() stereoN_to_S.inverse().display()
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
>>> from sage.all import *
>>> M.subset_family()
Set {S^2, U, V, W} of open subsets of the 2-dimensional topological manifold S^2
M.subset_family()
\(W\) is the open subset that is the complement of the two poles:
sage: N in W or S in W
False
>>> from sage.all import *
>>> N in W or S in W
False
N in W or S in W
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)
>>> from sage.all import *
>>> N in V, N in U
(True, False)
>>> S in U, S in V
(True, False)
N in V, N in U S in U, S in V
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))]
>>> from sage.all import *
>>> M.atlas()
[Chart (U, (x, y)), Chart (V, (u, v)),
Chart (W, (x, y)), Chart (W, (u, v))]
M.atlas()
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
>>> from sage.all import *
>>> p = M.point((Integer(1),Integer(2)), chart=stereoN, name='p'); p
Point p on the 2-dimensional topological manifold S^2
>>> p.parent()
2-dimensional topological manifold S^2
>>> p in W
True
p = M.point((1,2), chart=stereoN, name='p'); p p.parent() p in W
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)
>>> from sage.all import *
>>> stereoS(p)
(1/5, 2/5)
stereoS(p)
Given the definition of \(p\), we have of course:
sage: stereoN(p)
(1, 2)
>>> from sage.all import *
>>> stereoN(p)
(1, 2)
stereoN(p)
Similarly:
sage: stereoS(N)
(0, 0)
sage: stereoN(S)
(0, 0)
>>> from sage.all import *
>>> stereoS(N)
(0, 0)
>>> stereoN(S)
(0, 0)
stereoS(N) stereoN(S)
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
>>> from sage.all import *
>>> f = M.scalar_field({stereoN: atan(x**Integer(2)+y**Integer(2)), stereoS: pi/Integer(2)-atan(u**Integer(2)+v**Integer(2))},
... name='f')
>>> f
Scalar field f on the 2-dimensional topological manifold S^2
>>> 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)
>>> f(p)
arctan(5)
>>> f(N)
1/2*pi
>>> f(S)
0
>>> f.parent()
Algebra of scalar fields on the 2-dimensional topological manifold S^2
>>> f.parent().category()
Join of Category of commutative algebras over Symbolic Ring and Category of homsets of topological spaces
f = M.scalar_field({stereoN: atan(x^2+y^2), stereoS: pi/2-atan(u^2+v^2)}, name='f') f f.display() f(p) f(N) f(S) f.parent() f.parent().category()
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 ℂ*
>>> from sage.all import *
>>> M = Manifold(Integer(1), 'ℂ*', structure='topological', field='complex'); M
Complex 1-dimensional topological manifold ℂ*
M = Manifold(1, 'ℂ*', structure='topological', field='complex'); M
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')
>>> from sage.all import *
>>> U = M.open_subset('U')
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()
>>> from sage.all import *
>>> Z = U.chart(names=('z',)); (z,) = Z._first_ngens(1)
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 ℂ*
>>> from sage.all import *
>>> O = U.point((Integer(0),), chart=Z, name='O'); O
Point O on the Complex 1-dimensional topological manifold ℂ*
O = U.point((0,), chart=Z, name='O'); O
Another open subset of \(\CC^*\) is \(V = \CC^*\setminus\{O\}\):
sage: V = M.open_subset('V')
>>> from sage.all import *
>>> V = M.open_subset('V')
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 ℂ*
>>> from sage.all import *
>>> W = V.chart(names=('w',)); (w,) = W._first_ngens(1); W
Chart (V, (w,))
>>> inf = M.point((Integer(0),), chart=W, name='inf', latex_name=r'\infty')
>>> inf
Point inf on the Complex 1-dimensional topological manifold ℂ*
W.<w> = V.chart(); W inf = M.point((0,), chart=W, name='inf', latex_name=r'\infty') inf
To fully construct the Riemann sphere, we declare that it is the union of \(U\) and \(V\):
sage: M.declare_union(U,V)
>>> from sage.all import *
>>> M.declare_union(U,V)
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
>>> from sage.all import *
>>> Z_to_W = Z.transition_map(W, Integer(1)/z, intersection_name='A',
... restrictions1= z!=Integer(0), restrictions2= w!=Integer(0))
>>> Z_to_W
Change of coordinates from Chart (A, (z,)) to Chart (A, (w,))
>>> Z_to_W.display()
w = 1/z
>>> Z_to_W.inverse()
Change of coordinates from Chart (A, (w,)) to Chart (A, (z,))
>>> Z_to_W.inverse().display()
z = 1/w
Z_to_W = Z.transition_map(W, 1/z, intersection_name='A', restrictions1= z!=0, restrictions2= w!=0) Z_to_W Z_to_W.display() Z_to_W.inverse() Z_to_W.inverse().display()
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 ℂ*
>>> from sage.all import *
>>> i = M((I,), chart=Z, name='i'); i
Point i on the Complex 1-dimensional topological manifold ℂ*
i = M((I,), chart=Z, name='i'); i
Its coordinates w.r.t. the charts Z
and W
are:
sage: Z(i)
(I,)
sage: W(i)
(-I,)
>>> from sage.all import *
>>> Z(i)
(I,)
>>> W(i)
(-I,)
Z(i) W(i)
and we have:
sage: i in U
True
sage: i in V
True
>>> from sage.all import *
>>> i in U
True
>>> i in V
True
i in U i in V
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,))]
>>> from sage.all import *
>>> M.subset_family()
Set {A, U, V, ℂ*} of open subsets of the Complex 1-dimensional topological manifold ℂ*
>>> M.atlas()
[Chart (U, (z,)), Chart (V, (w,)), Chart (A, (z,)), Chart (A, (w,))]
M.subset_family() M.atlas()
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
>>> from sage.all import *
>>> f = M.constant_scalar_field(Integer(3)+Integer(2)*I, name='f'); f
Scalar field f on the Complex 1-dimensional topological manifold ℂ*
>>> f.display()
f: ℂ* → ℂ
on U: z ↦ 2*I + 3
on V: w ↦ 2*I + 3
>>> f(O)
2*I + 3
>>> f(i)
2*I + 3
>>> f(inf)
2*I + 3
>>> f.parent()
Algebra of scalar fields on the Complex 1-dimensional topological
manifold ℂ*
>>> f.parent().category()
Join of Category of commutative algebras over Symbolic Ring and Category of homsets of topological spaces
f = M.constant_scalar_field(3+2*I, name='f'); f f.display() f(O) f(i) f(inf) f.parent() f.parent().category()
AUTHORS:
Eric Gourgoulhon (2015): initial version
Travis Scrimshaw (2015): structure described via
TopologicalStructure
orRealTopologicalStructure
Michael Jung (2020): topological vector bundles and orientability
REFERENCES:
- sage.manifolds.manifold.Manifold(dim, name, latex_name=None, field='real', structure=None, start_index=0, **extra_kwds)[source]¶
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 nonnegative 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 manifoldname
– string; name (symbol) given to the manifoldlatex_name
– (default:None
) string; LaTeX symbol to denote the manifold; if none are provided, it is set toname
field
– (default:'real'
) field \(K\) on which the manifold is defined; allowed values are'real'
or an object of typeRealField
(e.g.RR
) for a manifold over \(\RR\)'complex'
or an object of typeComplexField
(e.g.CC
) for a manifold over \(\CC\)an object in the category of topological fields (see
Fields
andTopologicalSpaces
) 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 argumentsignature
(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 argumentsignature='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 chartextra_kwds
– keywords meaningful only for some specific types of manifolds:diff_degree
– (only for differentiable manifolds; default:infinity
): the degree of differentiabilityambient
– (only to construct a submanifold): the ambient manifoldmetric_name
– (only for pseudo-Riemannian manifolds; default:'g'
) string; name (symbol) given to the metricmetric_latex_name
– (only for pseudo-Riemannian manifolds; default:None
) string; LaTeX symbol to denote the metric; if none is provided, the symbol is set tometric_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; ifsignature
is not provided, \(S\) is set to the manifold’s dimension (Riemannian signature); for Lorentzian manifolds the valuessignature='positive'
(default) orsignature='negative'
are allowed to indicate the chosen signature convention.
OUTPUT:
a manifold of the specified type, as an instance of
TopologicalManifold
or one of its subclassesDifferentiableManifold
orPseudoRiemannianManifold
, or, if the keywordambient
is used, one of the subclassesTopologicalSubmanifold
,DifferentiableSubmanifold
, orPseudoRiemannianSubmanifold
.
EXAMPLES:
A 3-dimensional real topological manifold:
sage: M = Manifold(3, 'M', structure='topological'); M 3-dimensional topological manifold M
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M', structure='topological'); M 3-dimensional topological manifold M
M = Manifold(3, 'M', structure='topological'); 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
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M', structure='topological', field='real'); M 3-dimensional topological manifold M
M = Manifold(3, 'M', structure='topological', field='real'); M
A complex topological manifold:
sage: M = Manifold(3, 'M', structure='topological', field='complex'); M Complex 3-dimensional topological manifold M
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M', structure='topological', field='complex'); M Complex 3-dimensional topological manifold M
M = Manifold(3, 'M', structure='topological', field='complex'); 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
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M', structure='topological', field=QQ); M 3-dimensional topological manifold M over the Rational Field
M = Manifold(3, 'M', structure='topological', field=QQ); M
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
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M', field='real', structure='differentiable', ... diff_degree=Integer(4)); M 3-dimensional differentiable manifold M
M = Manifold(3, 'M', field='real', structure='differentiable', diff_degree=4); 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'
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M', structure='differentiable', diff_degree=Integer(4)) >>> M 3-dimensional differentiable manifold M >>> M.base_field_type() 'real'
M = Manifold(3, 'M', structure='differentiable', diff_degree=4) M M.base_field_type()
A 3-dimensional real smooth manifold:
sage: M = Manifold(3, 'M', structure='differentiable', diff_degree=+oo) sage: M 3-dimensional differentiable manifold M
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M', structure='differentiable', diff_degree=+oo) >>> M 3-dimensional differentiable manifold M
M = Manifold(3, 'M', structure='differentiable', diff_degree=+oo) M
Instead of
structure='differentiable', diff_degree=+oo
, it suffices to usestructure='smooth'
to get the same result:sage: M = Manifold(3, 'M', structure='smooth'); M 3-dimensional differentiable manifold M sage: M.diff_degree() +Infinity
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M', structure='smooth'); M 3-dimensional differentiable manifold M >>> M.diff_degree() +Infinity
M = Manifold(3, 'M', structure='smooth'); M M.diff_degree()
Actually, since
'smooth'
is the default value of the parameterstructure
, 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
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M'); M 3-dimensional differentiable manifold M >>> M.diff_degree() +Infinity
M = Manifold(3, 'M'); M M.diff_degree()
Other parameters can change the default of the parameter
structure
:sage: M = Manifold(3, 'M', diff_degree=0); M 3-dimensional topological manifold M sage: M = Manifold(3, 'M', diff_degree=2); M 3-dimensional differentiable manifold M sage: M = Manifold(3, 'M', metric_name='g'); M 3-dimensional Riemannian manifold M
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M', diff_degree=Integer(0)); M 3-dimensional topological manifold M >>> M = Manifold(Integer(3), 'M', diff_degree=Integer(2)); M 3-dimensional differentiable manifold M >>> M = Manifold(Integer(3), 'M', metric_name='g'); M 3-dimensional Riemannian manifold M
M = Manifold(3, 'M', diff_degree=0); M M = Manifold(3, 'M', diff_degree=2); M M = Manifold(3, 'M', metric_name='g'); M
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
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M', field='complex'); M 3-dimensional complex manifold M >>> M.diff_degree() +Infinity
M = Manifold(3, 'M', field='complex'); M M.diff_degree()
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
>>> from sage.all import * >>> N = Manifold(Integer(2), 'N', field='complex', ambient=M); N 2-dimensional differentiable submanifold N immersed in the 3-dimensional complex manifold M
N = Manifold(2, 'N', field='complex', ambient=M); N
The immersion \(N\to M\) has to be specified in a second stage, via the method
set_immersion()
orset_embedding()
.For more detailed examples, see the documentation of
TopologicalManifold
,DifferentiableManifold
andPseudoRiemannianManifold
, or the documentation ofTopologicalSubmanifold
,DifferentiableSubmanifold
andPseudoRiemannianSubmanifold
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()
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological') >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
M = Manifold(2, 'M', structure='topological') 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')
>>> from sage.all import * >>> M_old = M # for reference >>> M = Manifold(Integer(2), 'M', structure='topological')
M_old = M # for reference M = Manifold(2, 'M', structure='topological')
This results in a brand new object:
sage: M.atlas() []
>>> from sage.all import * >>> M.atlas() []
M.atlas()
The object
M_old
is intact:sage: M_old.atlas() [Chart (M, (x, y))]
>>> from sage.all import * >>> M_old.atlas() [Chart (M, (x, y))]
M_old.atlas()
Both objects have the same display:
sage: M 2-dimensional topological manifold M sage: M_old 2-dimensional topological manifold M
>>> from sage.all import * >>> M 2-dimensional topological manifold M >>> M_old 2-dimensional topological manifold M
M M_old
but they are different:
sage: M != M_old True
>>> from sage.all import * >>> M != M_old True
M != M_old
Let us introduce a chart on
M
, using the same coordinate symbols as forM_old
:sage: X.<x,y> = M.chart()
>>> from sage.all import * >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
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))]
>>> from sage.all import * >>> M.atlas() [Chart (M, (x, y))] >>> M_old.atlas() [Chart (M, (x, y))]
M.atlas() M_old.atlas()
but they are actually different:
sage: M.atlas()[0] != M_old.atlas()[0] True
>>> from sage.all import * >>> M.atlas()[Integer(0)] != M_old.atlas()[Integer(0)] True
M.atlas()[0] != M_old.atlas()[0]
Moreover, the two manifolds
M
andM_old
are still considered distinct:sage: M != M_old True
>>> from sage.all import * >>> M != M_old True
M != M_old
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 fromWithEqualityById
:sage: isinstance(M, sage.misc.fast_methods.WithEqualityById) True
>>> from sage.all import * >>> isinstance(M, sage.misc.fast_methods.WithEqualityById) True
isinstance(M, sage.misc.fast_methods.WithEqualityById)
- class sage.manifolds.manifold.TopologicalManifold(n, name, field, structure, base_manifold=None, latex_name=None, start_index=0, category=None, unique_tag=None)[source]¶
Bases:
ManifoldSubset
Topological manifold over a topological field \(K\).
Given a topological field \(K\) (in most applications, \(K = \RR\) or \(K = \CC\)) and a nonnegative 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 manifoldname
– string; name (symbol) given to the manifoldfield
– field \(K\) on which the manifold is defined; allowed values are'real'
or an object of typeRealField
(e.g.,RR
) for a manifold over \(\RR\)'complex'
or an object of typeComplexField
(e.g.,CC
) for a manifold over \(\CC\)an object in the category of topological fields (see
Fields
andTopologicalSpaces
) for other types of manifolds
structure
– manifold structure (seeTopologicalStructure
orRealTopologicalStructure
)base_manifold
– (default:None
) if notNone
, must be a topological manifold; the created object is then an open subset ofbase_manifold
latex_name
– (default:None
) string; LaTeX symbol to denote the manifold; if none are provided, it is set toname
start_index
– (default: 0) integer; lower value of the range of indices used for “indexed objects” on the manifold, e.g., coordinates in a chartcategory
– (default:None
) to specify the category; ifNone
,Manifolds(field)
is assumed (see the categoryManifolds
)unique_tag
– (default:None
) tag used to force the construction of a new object when all the other arguments have been used previously (withoutunique_tag
, theUniqueRepresentation
behavior inherited fromManifoldSubset
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
>>> from sage.all import * >>> M = Manifold(Integer(4), 'M', latex_name=r'\mathcal{M}', structure='topological') >>> M 4-dimensional topological manifold M >>> latex(M) \mathcal{M} >>> type(M) <class 'sage.manifolds.manifold.TopologicalManifold_with_category'> >>> M.base_field() Real Field with 53 bits of precision >>> dim(M) 4
M = Manifold(4, 'M', latex_name=r'\mathcal{M}', structure='topological') M latex(M) type(M) M.base_field() dim(M)
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]
>>> from sage.all import * >>> M = Manifold(Integer(4), 'M', structure='topological') >>> list(M.irange()) [0, 1, 2, 3] >>> M = Manifold(Integer(4), 'M', structure='topological', start_index=Integer(1)) >>> list(M.irange()) [1, 2, 3, 4] >>> list(Manifold(Integer(4), 'M', structure='topological', start_index=-Integer(2)).irange()) [-2, -1, 0, 1]
M = Manifold(4, 'M', structure='topological') list(M.irange()) M = Manifold(4, 'M', structure='topological', start_index=1) list(M.irange()) list(Manifold(4, 'M', structure='topological', start_index=-2).irange())
A complex manifold:
sage: N = Manifold(3, 'N', structure='topological', field='complex'); N Complex 3-dimensional topological manifold N
>>> from sage.all import * >>> N = Manifold(Integer(3), 'N', structure='topological', field='complex'); N Complex 3-dimensional topological manifold N
N = Manifold(3, 'N', structure='topological', field='complex'); N
A manifold over \(\QQ\):
sage: N = Manifold(6, 'N', structure='topological', field=QQ); N 6-dimensional topological manifold N over the Rational Field
>>> from sage.all import * >>> N = Manifold(Integer(6), 'N', structure='topological', field=QQ); N 6-dimensional topological manifold N over the Rational Field
N = Manifold(6, 'N', structure='topological', field=QQ); N
A manifold over \(\QQ_5\), the field of 5-adic numbers:
sage: N = Manifold(2, 'N', structure='topological', field=Qp(5)); N # needs sage.rings.padics 2-dimensional topological manifold N over the 5-adic Field with capped relative precision 20
>>> from sage.all import * >>> N = Manifold(Integer(2), 'N', structure='topological', field=Qp(Integer(5))); N # needs sage.rings.padics 2-dimensional topological manifold N over the 5-adic Field with capped relative precision 20
N = Manifold(2, 'N', structure='topological', field=Qp(5)); N # needs sage.rings.padics
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)) # needs sage.rings.padics True
>>> from sage.all import * >>> isinstance(M, Parent) True >>> M.category() Category of manifolds over Real Field with 53 bits of precision >>> from sage.categories.manifolds import Manifolds >>> M.category() is Manifolds(RR) True >>> M.category() is Manifolds(M.base_field()) True >>> M in Manifolds(RR) True >>> N in Manifolds(Qp(Integer(5))) # needs sage.rings.padics True
isinstance(M, Parent) M.category() from sage.categories.manifolds import Manifolds M.category() is Manifolds(RR) M.category() is Manifolds(M.base_field()) M in Manifolds(RR) N in Manifolds(Qp(5)) # needs sage.rings.padics
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
>>> from sage.all import * >>> X = M.chart(names=('t', 'x', 'y', 'z',)); (t, x, y, z,) = X._first_ngens(4) >>> p = M.an_element(); p Point on the 4-dimensional topological manifold M >>> p.parent() 4-dimensional topological manifold M >>> M.is_parent_of(p) True >>> p in M True
X.<t, x, y, z> = M.chart() p = M.an_element(); p p.parent() M.is_parent_of(p) p in M
The manifold’s points are instances of class
ManifoldPoint
:sage: isinstance(p, sage.manifolds.point.ManifoldPoint) True
>>> from sage.all import * >>> isinstance(p, sage.manifolds.point.ManifoldPoint) True
isinstance(p, sage.manifolds.point.ManifoldPoint)
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
>>> from sage.all import * >>> U = M.open_subset('U'); U Open subset U of the 4-dimensional topological manifold M >>> isinstance(U, sage.manifolds.manifold.TopologicalManifold) True >>> U.base_field() == M.base_field() True >>> dim(U) == dim(M) True >>> U.category() Join of Category of subobjects of sets and Category of manifolds over Real Field with 53 bits of precision
U = M.open_subset('U'); U isinstance(U, sage.manifolds.manifold.TopologicalManifold) U.base_field() == M.base_field() dim(U) == dim(M) U.category()
The manifold passes all the tests of the test suite relative to its category:
sage: TestSuite(M).run()
>>> from sage.all import * >>> TestSuite(M).run()
TestSuite(M).run()
See also
- atlas()[source]¶
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')
>>> from sage.all import * >>> M = Manifold(Integer(2), 'R^2', structure='topological')
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() []
>>> from sage.all import * >>> M.atlas() []
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))]
>>> from sage.all import * >>> c_cart = M.chart(names=('x', 'y',)); (x, y,) = c_cart._first_ngens(2) >>> M.atlas() [Chart (R^2, (x, y))]
c_cart.<x,y> = M.chart() M.atlas()
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))]
>>> from sage.all import * >>> U = M.open_subset('U', coord_def={c_cart: (y!=Integer(0),x<Integer(0))}) >>> U.atlas() [Chart (U, (x, y))] >>> M.atlas() [Chart (R^2, (x, y)), Chart (U, (x, y))]
U = M.open_subset('U', coord_def={c_cart: (y!=0,x<0)}) U.atlas() M.atlas()
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))]
>>> from sage.all import * >>> c_spher = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi', names=('r', 'ph',)); (r, ph,) = c_spher._first_ngens(2) >>> U.atlas() [Chart (U, (x, y)), Chart (U, (r, ph))] >>> M.atlas() [Chart (R^2, (x, y)), Chart (U, (x, y)), Chart (U, (r, ph))]
c_spher.<r, ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi') U.atlas() M.atlas()
See also
- base_field()[source]¶
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
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M', structure='topological') >>> M.base_field() Real Field with 53 bits of precision >>> M = Manifold(Integer(3), 'M', structure='topological', field='complex') >>> M.base_field() Complex Field with 53 bits of precision >>> M = Manifold(Integer(3), 'M', structure='topological', field=QQ) >>> M.base_field() Rational Field
M = Manifold(3, 'M', structure='topological') M.base_field() M = Manifold(3, 'M', structure='topological', field='complex') M.base_field() M = Manifold(3, 'M', structure='topological', field=QQ) M.base_field()
- base_field_type()[source]¶
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'
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M', structure='topological') >>> M.base_field_type() 'real' >>> M = Manifold(Integer(3), 'M', structure='topological', field='complex') >>> M.base_field_type() 'complex' >>> M = Manifold(Integer(3), 'M', structure='topological', field=QQ) >>> M.base_field_type() 'neither_real_nor_complex'
M = Manifold(3, 'M', structure='topological') M.base_field_type() M = Manifold(3, 'M', structure='topological', field='complex') M.base_field_type() M = Manifold(3, 'M', structure='topological', field=QQ) M.base_field_type()
- chart(coordinates='', names=None, calc_method=None, coord_restrictions=None)[source]¶
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 belownames
– (default:None
) unused argument, except ifcoordinates
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'
: SymPyNone
: 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 (':'
):The coordinate symbol (a letter or a few letters).
(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 boundsa
andb
can be+/-Infinity
,Inf
,infinity
,inf
oroo
. 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.(optional) Indicator of the periodic character of the coordinate, either as
period=T
, whereT
is the period, or, for manifolds over \(\RR\) only, as the keywordperiodic
(the value of the period is then deduced from the interval \(I\) declared in field 2; see the example below)(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 argumentcoordinates
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
orx^2 + y^2 != 0
. The items of the list (or set or frozenset)coord_restrictions
are combined with theand
operator; if some restrictions are to be combined with theor
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 listcoord_restrictions
contains only one item, this item can be passed as such, i.e. writingx > y
instead of the single element list[x > y]
. If the chart variables have not been declared as variables yet,coord_restrictions
must belambda
-quoted.OUTPUT:
the created chart, as an instance of
Chart
or one of its subclasses, likeRealDiffChart
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)
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological') >>> X = M.chart('x y'); X Chart (M, (x, y)) >>> X[Integer(0)] x >>> X[Integer(1)] y >>> X[:] (x, y)
M = Manifold(2, 'M', structure='topological') X = M.chart('x y'); X X[0] X[1] X[:]
The declared coordinates are not known at the global level:
sage: y Traceback (most recent call last): ... NameError: name 'y' is not defined
>>> from sage.all import * >>> y Traceback (most recent call last): ... NameError: name 'y' is not defined
y
They can be recovered by the operator
[:]
applied to the chart:sage: (x, y) = X[:] sage: y y sage: type(y) <class 'sage.symbolic.expression.Expression'>
>>> from sage.all import * >>> (x, y) = X[:] >>> y y >>> type(y) <class 'sage.symbolic.expression.Expression'>
(x, y) = X[:] y type(y)
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))
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological') >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2); X Chart (M, (x, y))
M = Manifold(2, 'M', structure='topological') X.<x,y> = M.chart(); X
Indeed, the declared coordinates are then known at the global level:
sage: y y sage: (x,y) == X[:] True
>>> from sage.all import * >>> y y >>> (x,y) == X[:] True
y (x,y) == X[:]
Actually the instruction
X.<x,y> = M.chart()
is equivalent to the combination of the two instructionsX = M.chart('x y')
and(x,y) = X[:]
.As an example of coordinate ranges and LaTeX symbols passed via the string
coordinates
tochart()
, 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)
>>> from sage.all import * >>> U = M.open_subset('U', coord_def={X: x**Integer(2)+y**Integer(2) != Integer(0)}) >>> P = U.chart(r'r:(0,+oo) ph:(0,2*pi):periodic:\phi', names=('r', 'ph',)); (r, ph,) = P._first_ngens(2); P Chart (U, (r, ph)) >>> P.coord_range() r: (0, +oo); ph: [0, 2*pi] (periodic) >>> latex(P) \left(U,(r, {\phi})\right)
U = M.open_subset('U', coord_def={X: x^2+y^2 != 0}) P.<r,ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):periodic:\phi'); P P.coord_range() latex(P)
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
>>> from sage.all import * >>> D = Manifold(Integer(2), 'D', structure='topological') >>> X = D.chart(coord_restrictions=lambda x,y: [x**Integer(2)+y**Integer(2)<Integer(1), x>Integer(0)], names=('x', 'y',)); (x, y,) = X._first_ngens(2); X Chart (D, (x, y)) >>> X.valid_coordinates(Integer(0), Integer(0)) False >>> X.valid_coordinates(Integer(1)/Integer(2), Integer(0)) True
D = Manifold(2, 'D', structure='topological') X.<x,y> = D.chart(coord_restrictions=lambda x,y: [x^2+y^2<1, x>0]); X X.valid_coordinates(0, 0) X.valid_coordinates(1/2, 0)
See the documentation of classes
Chart
andRealChart
for more examples, especially regarding the coordinates ranges and restrictions.
- constant_scalar_field(value, name=None, latex_name=None)[source]¶
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 coordinatesname
– (default:None
) name given to the scalar fieldlatex_name
– (default:None
) LaTeX symbol to denote the scalar field; ifNone
, the LaTeX symbol is set toname
OUTPUT:
instance of
ScalarField
representing the scalar field whose constant value isvalue
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
>>> 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() >>> f = M.constant_scalar_field(-Integer(1)) ; f Scalar field on the 2-dimensional topological manifold M >>> f.display() M → ℝ on U: (x, y) ↦ -1 on V: (u, v) ↦ -1
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() f = M.constant_scalar_field(-1) ; f f.display()
We have:
sage: f.restrict(U) == U.constant_scalar_field(-1) True sage: M.constant_scalar_field(0) is M.zero_scalar_field() True
>>> from sage.all import * >>> f.restrict(U) == U.constant_scalar_field(-Integer(1)) True >>> M.constant_scalar_field(Integer(0)) is M.zero_scalar_field() True
f.restrict(U) == U.constant_scalar_field(-1) M.constant_scalar_field(0) is M.zero_scalar_field()
See also
- continuous_map(codomain, coord_functions=None, chart1=None, chart2=None, name=None, latex_name=None)[source]¶
Define a continuous map from
self
tocodomain
.INPUT:
codomain
–TopologicalManifold
; the map’s codomaincoord_functions
– (default:None
) if notNone
, 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 onself
andchart2
a chart oncodomain
);(ii) a single coordinate expression in a given pair of charts, the latter being provided by the arguments
chart1
andchart2
;
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 onself
defining the start coordinates involved incoord_functions
for case (ii); ifNone
, the coordinates are assumed to refer to the default chart ofself
chart2
– (default:None
; used only in case (ii) above) chart oncodomain
defining the target coordinates involved incoord_functions
for case (ii); ifNone
, the coordinates are assumed to refer to the default chart ofcodomain
name
– (default:None
) name given to the continuous maplatex_name
– (default:None
) LaTeX symbol to denote the continuous map; ifNone
, the LaTeX symbol is set toname
OUTPUT:
the continuous map as an instance of
ContinuousMap
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
>>> from sage.all import * >>> M = Manifold(Integer(2), 'S^2', structure='topological') >>> U = M.open_subset('U') >>> c_spher = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi', names=('th', 'ph',)); (th, ph,) = c_spher._first_ngens(2) >>> N = Manifold(Integer(3), 'R^3', latex_name=r'\RR^3', structure='topological') >>> c_cart = N.chart(names=('x', 'y', 'z',)); (x, y, z,) = c_cart._first_ngens(3)# Cartesian coord. on R^3 >>> Phi = U.continuous_map(N, (sin(th)*cos(ph), sin(th)*sin(ph), cos(th)), ... name='Phi', latex_name=r'\Phi') >>> 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
M = Manifold(2, 'S^2', structure='topological') U = M.open_subset('U') c_spher.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') N = Manifold(3, 'R^3', latex_name=r'\RR^3', structure='topological') c_cart.<x,y,z> = N.chart() # Cartesian coord. on R^3 Phi = U.continuous_map(N, (sin(th)*cos(ph), sin(th)*sin(ph), cos(th)), name='Phi', latex_name=r'\Phi') Phi
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
>>> from sage.all import * >>> 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') >>> Phi1 == Phi True
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') Phi1 == Phi
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
>>> from sage.all import * >>> p = U.point((pi/Integer(2), pi)) ; p Point on the 2-dimensional topological manifold S^2 >>> Phi(p) Point on the 3-dimensional topological manifold R^3 >>> Phi(p).coord(c_cart) (-1, 0, 0) >>> Phi1(p) == Phi(p) True
p = U.point((pi/2, pi)) ; p Phi(p) Phi(p).coord(c_cart) Phi1(p) == Phi(p)
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)[source]¶
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 1chart2
– 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))
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological') >>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2) >>> c_uv = M.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> 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)) >>> 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))
M = Manifold(2, 'M', structure='topological') c_xy.<x,y> = M.chart() c_uv.<u,v> = M.chart() c_xy.transition_map(c_uv, (x+y, x-y)) # defines the coord. change M.coord_change(c_xy, c_uv) # returns the coord. change defined above
- coord_changes()[source]¶
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))}
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological') >>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2) >>> c_uv = M.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> xy_to_uv = c_xy.transition_map(c_uv, [x+y, x-y]) >>> M.coord_changes() {(Chart (M, (x, y)), Chart (M, (u, v))): Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v))} >>> uv_to_xy = xy_to_uv.inverse() >>> 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))} >>> c_rs = M.chart(names=('r', 's',)); (r, s,) = c_rs._first_ngens(2) >>> uv_to_rs = c_uv.transition_map(c_rs, [-u+Integer(2)*v, Integer(3)*u-v]) >>> 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))} >>> xy_to_rs = uv_to_rs * xy_to_uv >>> 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))}
M = Manifold(2, 'M', structure='topological') c_xy.<x,y> = M.chart() c_uv.<u,v> = M.chart() xy_to_uv = c_xy.transition_map(c_uv, [x+y, x-y]) M.coord_changes() uv_to_xy = xy_to_uv.inverse() M.coord_changes() # random (dictionary output) c_rs.<r,s> = M.chart() uv_to_rs = c_uv.transition_map(c_rs, [-u+2*v, 3*u-v]) M.coord_changes() # random (dictionary output) xy_to_rs = uv_to_rs * xy_to_uv M.coord_changes() # random (dictionary output)
- default_chart()[source]¶
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))
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological') >>> M.chart('x y') Chart (M, (x, y)) >>> M.chart('u v') Chart (M, (u, v)) >>> M.default_chart() Chart (M, (x, y)) >>> A = M.open_subset('A') >>> A.chart('t z') Chart (A, (t, z)) >>> A.default_chart() Chart (A, (t, z))
M = Manifold(2, 'M', structure='topological') M.chart('x y') M.chart('u v') M.default_chart() A = M.open_subset('A') A.chart('t z') A.default_chart()
- dim()[source]¶
Return the dimension of the manifold over its base field.
EXAMPLES:
sage: M = Manifold(2, 'M', structure='topological') sage: M.dimension() 2
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological') >>> M.dimension() 2
M = Manifold(2, 'M', structure='topological') M.dimension()
A shortcut is
dim()
:sage: M.dim() 2
>>> from sage.all import * >>> M.dim() 2
M.dim()
The Sage global function
dim
can also be used:sage: dim(M) 2
>>> from sage.all import * >>> dim(M) 2
dim(M)
- dimension()[source]¶
Return the dimension of the manifold over its base field.
EXAMPLES:
sage: M = Manifold(2, 'M', structure='topological') sage: M.dimension() 2
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological') >>> M.dimension() 2
M = Manifold(2, 'M', structure='topological') M.dimension()
A shortcut is
dim()
:sage: M.dim() 2
>>> from sage.all import * >>> M.dim() 2
M.dim()
The Sage global function
dim
can also be used:sage: dim(M) 2
>>> from sage.all import * >>> dim(M) 2
dim(M)
- get_chart(coordinates, domain=None)[source]¶
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 spacedomain
– (default:None
) string containing the name of the chart’s domain, which must be a subset of the current manifold; ifNone
, the current manifold is assumed
OUTPUT:
instance of
Chart
(or of the subclassRealChart
) 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
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological') >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2) >>> M.get_chart('x y') Chart (M, (x, y)) >>> M.get_chart('x y') is X True >>> U = M.open_subset('U', coord_def={X: (y!=Integer(0),x<Integer(0))}) >>> Y = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi', names=('r', 'ph',)); (r, ph,) = Y._first_ngens(2) >>> M.atlas() [Chart (M, (x, y)), Chart (U, (x, y)), Chart (U, (r, ph))] >>> M.get_chart('x y', domain='U') Chart (U, (x, y)) >>> M.get_chart('x y', domain='U') is X.restrict(U) True >>> U.get_chart('r ph') Chart (U, (r, ph)) >>> M.get_chart('r ph', domain='U') Chart (U, (r, ph)) >>> M.get_chart('r ph', domain='U') is Y True
M = Manifold(2, 'M', structure='topological') X.<x,y> = M.chart() M.get_chart('x y') M.get_chart('x y') is X U = M.open_subset('U', coord_def={X: (y!=0,x<0)}) Y.<r, ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi') M.atlas() M.get_chart('x y', domain='U') M.get_chart('x y', domain='U') is X.restrict(U) U.get_chart('r ph') M.get_chart('r ph', domain='U') M.get_chart('r ph', domain='U') is Y
- has_orientation()[source]¶
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()
returnsFalse
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, seeset_orientation()
.EXAMPLES:
The trivial case:
sage: M = Manifold(3, 'M', structure='top') sage: c.<x,y,z> = M.chart() sage: M.has_orientation() True
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M', structure='top') >>> c = M.chart(names=('x', 'y', 'z',)); (x, y, z,) = c._first_ngens(3) >>> M.has_orientation() True
M = Manifold(3, 'M', structure='top') c.<x,y,z> = M.chart() M.has_orientation()
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
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='top') >>> U = M.open_subset('U'); V = M.open_subset('V') >>> M.declare_union(U, V) >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2); c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> M.has_orientation() False >>> M.set_orientation([c_xy, c_uv]) >>> M.has_orientation() True
M = Manifold(2, 'M', structure='top') U = M.open_subset('U'); V = M.open_subset('V') M.declare_union(U, V) c_xy.<x,y> = U.chart(); c_uv.<u,v> = V.chart() M.has_orientation() M.set_orientation([c_xy, c_uv]) M.has_orientation()
- homeomorphism(codomain, coord_functions=None, chart1=None, chart2=None, name=None, latex_name=None)[source]¶
Define a homeomorphism between the current manifold and another one.
See
ContinuousMap
for a complete documentation.INPUT:
codomain
–TopologicalManifold
; codomain of the homeomorphismcoord_functions
– (default:None
) if notNone
, 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 onself
andchart2
a chart oncodomain
);(ii) a single coordinate expression in a given pair of charts, the latter being provided by the arguments
chart1
andchart2
;
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 onself
defining the start coordinates involved incoord_functions
for case (ii); ifNone
, the coordinates are assumed to refer to the default chart ofself
chart2
– (default:None
; used only in case (ii) above) chart oncodomain
defining the target coordinates involved incoord_functions
for case (ii); ifNone
, the coordinates are assumed to refer to the default chart ofcodomain
name
– (default:None
) name given to the homeomorphismlatex_name
– (default:None
) LaTeX symbol to denote the homeomorphism; ifNone
, the LaTeX symbol is set toname
OUTPUT:
the homeomorphism, as an instance of
ContinuousMap
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))
>>> from sage.all import * >>> forget() # for doctests only >>> M = Manifold(Integer(2), 'M', structure='topological') # the open unit disk >>> c_xy = M.chart('x:(-1,1) y:(-1,1)', coord_restrictions=lambda x,y: x**Integer(2)+y**Integer(2)<Integer(1), names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2) ... # Cartesian coord on M >>> N = Manifold(Integer(2), 'N', structure='topological') # R^2 >>> c_XY = N.chart(names=('X', 'Y',)); (X, Y,) = c_XY._first_ngens(2)# canonical coordinates on R^2 >>> Phi = M.homeomorphism(N, [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 2-dimensional topological manifold M to the 2-dimensional topological manifold N >>> Phi.display() Phi: M → N (x, y) ↦ (X, Y) = (x/sqrt(-x^2 - y^2 + 1), y/sqrt(-x^2 - y^2 + 1))
forget() # for doctests only M = Manifold(2, 'M', structure='topological') # the open unit disk 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 N = Manifold(2, 'N', structure='topological') # R^2 c_XY.<X,Y> = N.chart() # canonical coordinates on R^2 Phi = M.homeomorphism(N, [x/sqrt(1-x^2-y^2), y/sqrt(1-x^2-y^2)], name='Phi', latex_name=r'\Phi') Phi Phi.display()
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))
>>> from sage.all import * >>> Phi**(-Integer(1)) Homeomorphism Phi^(-1) from the 2-dimensional topological manifold N to the 2-dimensional topological manifold M >>> (Phi**(-Integer(1))).display() Phi^(-1): N → M (X, Y) ↦ (x, y) = (X/sqrt(X^2 + Y^2 + 1), Y/sqrt(X^2 + Y^2 + 1))
Phi^(-1) (Phi^(-1)).display()
See the documentation of
ContinuousMap
for more examples.
- identity_map()[source]¶
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:
the identity map as an instance of
ContinuousMap
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)
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological', field='complex') >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2) >>> id = M.identity_map(); id Identity map Id_M of the Complex 2-dimensional topological manifold M >>> 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 >>> id.display() Id_M: M → M (x, y) ↦ (x, y)
M = Manifold(2, 'M', structure='topological', field='complex') X.<x,y> = M.chart() id = M.identity_map(); id id.parent() id.display()
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
>>> from sage.all import * >>> p = M((Integer(1)+I, Integer(3)-I), name='p'); p Point p on the Complex 2-dimensional topological manifold M >>> id(p) Point p on the Complex 2-dimensional topological manifold M >>> id(p) == p True
p = M((1+I, 3-I), name='p'); p id(p) id(p) == p
See also
See
ContinuousMap
for the complete documentation.
- index_generator(nb_indices)[source]¶
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)]
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological', start_index=Integer(1)) >>> list(M.index_generator(Integer(2))) [(1, 1), (1, 2), (2, 1), (2, 2)]
M = Manifold(2, 'M', structure='topological', start_index=1) list(M.index_generator(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)]
>>> from sage.all import * >>> for ind1 in M.index_generator(Integer(2)): ... print("{} : {}".format(ind1, list(M.index_generator(Integer(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)]
for ind1 in M.index_generator(2): print("{} : {}".format(ind1, list(M.index_generator(2))))
- irange(start=None, end=None)[source]¶
Single index generator.
INPUT:
start
– (default:None
) initial value \(i_0\) of the index; ifNone
, the value returned bystart_index()
is assumedend
– (default:None
) final value \(i_n\) of the index; ifNone
, the value returned bystart_index()
plus \(n - 1\), where \(n\) is the manifold dimension, is assumed
OUTPUT: an iterable index, starting from \(i_0\) and ending at \(i_0 + i_n\)
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(start=2)) [2, 3] sage: list(M.irange(end=2)) [0, 1, 2] sage: list(M.irange(start=1, end=2)) [1, 2]
>>> from sage.all import * >>> M = Manifold(Integer(4), 'M', structure='topological') >>> list(M.irange()) [0, 1, 2, 3] >>> list(M.irange(start=Integer(2))) [2, 3] >>> list(M.irange(end=Integer(2))) [0, 1, 2] >>> list(M.irange(start=Integer(1), end=Integer(2))) [1, 2]
M = Manifold(4, 'M', structure='topological') list(M.irange()) list(M.irange(start=2)) list(M.irange(end=2)) list(M.irange(start=1, end=2))
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(start=2)) [2, 3, 4] sage: list(M.irange(end=2)) [1, 2] sage: list(M.irange(start=2, end=3)) [2, 3]
>>> from sage.all import * >>> M = Manifold(Integer(4), 'M', structure='topological', start_index=Integer(1)) >>> list(M.irange()) [1, 2, 3, 4] >>> list(M.irange(start=Integer(2))) [2, 3, 4] >>> list(M.irange(end=Integer(2))) [1, 2] >>> list(M.irange(start=Integer(2), end=Integer(3))) [2, 3]
M = Manifold(4, 'M', structure='topological', start_index=1) list(M.irange()) list(M.irange(start=2)) list(M.irange(end=2)) list(M.irange(start=2, end=3))
In general, one has always:
sage: next(M.irange()) == M.start_index() True
>>> from sage.all import * >>> next(M.irange()) == M.start_index() True
next(M.irange()) == M.start_index()
- is_manifestly_coordinate_domain()[source]¶
Return
True
if the manifold is known to be the domain of some coordinate chart andFalse
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
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological') >>> U = M.open_subset('U') >>> X = U.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2) >>> U.is_manifestly_coordinate_domain() True >>> M.is_manifestly_coordinate_domain() False >>> Y = M.chart(names=('u', 'v',)); (u, v,) = Y._first_ngens(2) >>> M.is_manifestly_coordinate_domain() True
M = Manifold(2, 'M', structure='topological') U = M.open_subset('U') X.<x,y> = U.chart() U.is_manifestly_coordinate_domain() M.is_manifestly_coordinate_domain() Y.<u,v> = M.chart() M.is_manifestly_coordinate_domain()
- is_open()[source]¶
Return if
self
is an open set.In the present case (manifold or open subset of it), always return
True
.
- one_scalar_field()[source]¶
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 ofself
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
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological') >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2) >>> f = M.one_scalar_field(); f Scalar field 1 on the 2-dimensional topological manifold M >>> f.display() 1: M → ℝ (x, y) ↦ 1 >>> f.parent() Algebra of scalar fields on the 2-dimensional topological manifold M >>> f is M.scalar_field_algebra().one() True
M = Manifold(2, 'M', structure='topological') X.<x,y> = M.chart() f = M.one_scalar_field(); f f.display() f.parent() f is M.scalar_field_algebra().one()
- open_subset(name, latex_name=None, coord_def={}, supersets=None)[source]¶
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 subsetlatex_name
– (default:None
) LaTeX symbol to denote the subset; if none are provided, it is set toname
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 subsetsupersets
– (default: onlyself
) list of sets that the new open subset is a subset of
OUTPUT: the open subset, as an instance of
TopologicalManifold
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
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological') >>> A = M.open_subset('A'); A Open subset A of the 2-dimensional topological manifold M
M = Manifold(2, 'M', structure='topological') A = M.open_subset('A'); A
As an open subset of a topological manifold,
A
is itself a topological manifold, on the same topological field and of the same dimension asM
: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
>>> from sage.all import * >>> isinstance(A, sage.manifolds.manifold.TopologicalManifold) True >>> A.base_field() == M.base_field() True >>> dim(A) == dim(M) True >>> A.category() is M.category().Subobjects() True
isinstance(A, sage.manifolds.manifold.TopologicalManifold) A.base_field() == M.base_field() dim(A) == dim(M) A.category() is M.category().Subobjects()
Creating an open subset of
A
:sage: B = A.open_subset('B'); B Open subset B of the 2-dimensional topological manifold M
>>> from sage.all import * >>> B = A.open_subset('B'); B Open subset B of the 2-dimensional topological manifold M
B = A.open_subset('B'); B
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
>>> from sage.all import * >>> 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} >>> B.is_subset(A) True >>> B.is_subset(M) True
frozenset(A.subsets()) # random (set output) B.is_subset(A) B.is_subset(M)
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
>>> from sage.all import * >>> M = Manifold(Integer(2), 'R^2', structure='topological') >>> c_cart = M.chart(names=('x', 'y',)); (x, y,) = c_cart._first_ngens(2)# Cartesian coordinates on R^2 >>> U = M.open_subset('U', coord_def={c_cart: x**Integer(2)+y**Integer(2)<Integer(1)}); U Open subset U of the 2-dimensional topological manifold R^2
M = Manifold(2, 'R^2', structure='topological') c_cart.<x,y> = M.chart() # Cartesian coordinates on R^2 U = M.open_subset('U', coord_def={c_cart: x^2+y^2<1}); U
Since the argument
coord_def
has been set,U
is automatically provided with a chart, which is the restriction of the Cartesian one toU
:sage: U.atlas() [Chart (U, (x, y))]
>>> from sage.all import * >>> U.atlas() [Chart (U, (x, y))]
U.atlas()
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
>>> from sage.all import * >>> M.point((Integer(0),Integer(0))) in U True >>> M.point((Integer(1)/Integer(2),Integer(1)/Integer(3))) in U True >>> M.point((Integer(1),Integer(2))) in U False
M.point((0,0)) in U M.point((1/2,1/3)) in U M.point((1,2)) in U
- options = Current options for manifolds - omit_function_arguments: False - textbook_output: True[source]¶
- orientation()[source]¶
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 detailsThe 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))]
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M', structure='top') >>> c = M.chart(names=('x', 'y', 'z',)); (x, y, z,) = c._first_ngens(3) >>> M.orientation() [Chart (M, (x, y, z))]
M = Manifold(3, 'M', structure='top') c.<x,y,z> = M.chart() M.orientation()
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() []
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='top') >>> U = M.open_subset('U'); V = M.open_subset('V') >>> M.declare_union(U, V) >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2); c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> M.orientation() []
M = Manifold(2, 'M', structure='top') U = M.open_subset('U'); V = M.open_subset('V') M.declare_union(U, V) c_xy.<x,y> = U.chart(); c_uv.<u,v> = V.chart() 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))]
>>> from sage.all import * >>> M.set_orientation([c_xy, c_uv]) >>> M.orientation() [Chart (U, (x, y)), Chart (V, (u, v))]
M.set_orientation([c_xy, c_uv]) M.orientation()
The orientation on submanifolds are inherited from the ambient manifold:
sage: W = U.intersection(V, name='W') sage: W.orientation() [Chart (W, (x, y))]
>>> from sage.all import * >>> W = U.intersection(V, name='W') >>> W.orientation() [Chart (W, (x, y))]
W = U.intersection(V, name='W') W.orientation()
- scalar_field(coord_expression=None, chart=None, name=None, latex_name=None)[source]¶
Define a scalar field on the manifold.
See
ScalarField
(orDiffScalarField
if the manifold is differentiable) for a complete documentation.INPUT:
coord_expression
– (default:None
) coordinate expression(s) of the scalar field; this can be eithera 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 argumentchart
a dictionary of coordinate expressions, with the charts as keys
chart
– (default:None
) chart defining the coordinates used incoord_expression
when the latter is a single coordinate expression; ifNone
, the default chart of the open set is assumed; ifchart=='all'
,coord_expression
is assumed to be independent of the chart (constant scalar field)name
– (default:None
) name given to the scalar fieldlatex_name
– (default:None
) LaTeX symbol to denote the scalar field; ifNone
, the LaTeX symbol is set toname
If
coord_expression
isNone
or does not fully specified the scalar field, other coordinate expressions can be added subsequently by means of the methodsadd_expr()
,add_expr_by_continuation()
, orset_expr()
OUTPUT:
instance of
ScalarField
(or of the subclassDiffScalarField
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
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M', structure='topological') >>> U = M.open_subset('U') >>> c_xyz = U.chart(names=('x', 'y', 'z',)); (x, y, z,) = c_xyz._first_ngens(3) >>> 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 >>> f.display() F: U → ℝ (x, y, z) ↦ cos(y)*sin(x) + z >>> f.parent() Algebra of scalar fields on the Open subset U of the 3-dimensional topological manifold M >>> f in U.scalar_field_algebra() True
M = Manifold(3, 'M', structure='topological') U = M.open_subset('U') c_xyz.<x,y,z> = U.chart() f = U.scalar_field(sin(x)*cos(y) + z, name='F'); f f.display() f.parent() f in U.scalar_field_algebra()
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
>>> from sage.all import * >>> f = U.scalar_field(sin(x)*cos(y) + z, chart=c_xyz, name='F') >>> f.display() F: U → ℝ (x, y, z) ↦ cos(y)*sin(x) + z
f = U.scalar_field(sin(x)*cos(y) + z, chart=c_xyz, name='F') f.display()
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
>>> from sage.all import * >>> f = U.scalar_field({c_xyz: sin(x)*cos(y) + z}, name='F') >>> f.display() F: U → ℝ (x, y, z) ↦ cos(y)*sin(x) + z
f = U.scalar_field({c_xyz: sin(x)*cos(y) + z}, name='F') f.display()
See the documentation of class
ScalarField
for more examples.
- scalar_field_algebra()[source]¶
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
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M', structure='topological') >>> U = M.open_subset('U') >>> CU = U.scalar_field_algebra() ; CU Algebra of scalar fields on the Open subset U of the 3-dimensional topological manifold M >>> CU.category() Join of Category of commutative algebras over Symbolic Ring and Category of homsets of topological spaces >>> CU.zero() Scalar field zero on the Open subset U of the 3-dimensional topological manifold M
M = Manifold(3, 'M', structure='topological') U = M.open_subset('U') CU = U.scalar_field_algebra() ; CU CU.category() CU.zero()
The output is cached:
sage: U.scalar_field_algebra() is CU True
>>> from sage.all import * >>> U.scalar_field_algebra() is CU True
U.scalar_field_algebra() is CU
- set_calculus_method(method)[source]¶
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')
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological') >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2) >>> f = M.scalar_field(x**Integer(2) + cos(y)*sin(x), name='F')
M = Manifold(2, 'M', structure='topological') X.<x,y> = M.chart() f = M.scalar_field(x^2 + cos(y)*sin(x), name='F')
By default, the coordinate expression of
f
returned byexpr()
is a Sage’s symbolic expression:sage: f.expr() x^2 + cos(y)*sin(x) sage: type(f.expr()) <class 'sage.symbolic.expression.Expression'> sage: parent(f.expr()) Symbolic Ring sage: f.display() F: M → ℝ (x, y) ↦ x^2 + cos(y)*sin(x)
>>> from sage.all import * >>> f.expr() x^2 + cos(y)*sin(x) >>> type(f.expr()) <class 'sage.symbolic.expression.Expression'> >>> parent(f.expr()) Symbolic Ring >>> f.display() F: M → ℝ (x, y) ↦ x^2 + cos(y)*sin(x)
f.expr() type(f.expr()) parent(f.expr()) f.display()
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)
>>> from sage.all import * >>> M.set_calculus_method('sympy') >>> f.expr() x**2 + sin(x)*cos(y) >>> type(f.expr()) <class 'sympy.core.add.Add'> >>> parent(f.expr()) <class 'sympy.core.add.Add'> >>> f.display() F: M → ℝ (x, y) ↦ x**2 + sin(x)*cos(y)
M.set_calculus_method('sympy') f.expr() type(f.expr()) parent(f.expr()) f.display()
Back to the Symbolic Ring:
sage: M.set_calculus_method('SR') sage: f.display() F: M → ℝ (x, y) ↦ x^2 + cos(y)*sin(x)
>>> from sage.all import * >>> M.set_calculus_method('SR') >>> f.display() F: M → ℝ (x, y) ↦ x^2 + cos(y)*sin(x)
M.set_calculus_method('SR') f.display()
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 (*)
>>> from sage.all import * >>> M.set_calculus_method('sympy') >>> Y = M.chart(names=('u', 'v',)); (u, v,) = Y._first_ngens(2)# a new chart >>> Y.calculus_method() Available calculus methods (* = current): - SR (default) - sympy (*)
M.set_calculus_method('sympy') Y.<u,v> = M.chart() # a new chart Y.calculus_method()
See also
calculus_method()
for a control of the calculus method chart by chart
- set_default_chart(chart)[source]¶
Changing the default chart on
self
.INPUT:
chart
– a chart (must be defined on some subsetself
)
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))
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological') >>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2) >>> c_uv = M.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> M.default_chart() Chart (M, (x, y)) >>> M.set_default_chart(c_uv) >>> M.default_chart() Chart (M, (u, v))
M = Manifold(2, 'M', structure='topological') c_xy.<x,y> = M.chart() c_uv.<u,v> = M.chart() M.default_chart() M.set_default_chart(c_uv) M.default_chart()
- set_orientation(orientation)[source]¶
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))]
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='top') >>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2); c_uv = M.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> M.set_orientation(c_uv) >>> M.orientation() [Chart (M, (u, v))]
M = Manifold(2, 'M', structure='top') c_xy.<x,y> = M.chart(); c_uv.<u,v> = M.chart() M.set_orientation(c_uv) M.orientation()
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))]
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='top') >>> U = M.open_subset('U'); V = M.open_subset('V') >>> M.declare_union(U, V) >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2); c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2) >>> M.set_orientation([c_xy, c_uv]) >>> M.orientation() [Chart (U, (x, y)), Chart (V, (u, v))]
M = Manifold(2, 'M', structure='top') U = M.open_subset('U'); V = M.open_subset('V') M.declare_union(U, V) c_xy.<x,y> = U.chart(); c_uv.<u,v> = V.chart() M.set_orientation([c_xy, c_uv]) M.orientation()
- set_simplify_function(simplifying_func, method=None)[source]¶
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 functionf
of a single argumentexpr
such thatf(expr)
returns an object of the same type asexpr
(hopefully the simplified version ofexpr
), this type beingExpression
ifmethod
='SR'
a SymPy type if
method
='sympy'
method
– (default:None
) string defining the calculus method for whichsimplifying_func
is provided; must be one of'SR'
: Sage’s default symbolic engine (Symbolic Ring)'sympy'
: SymPyNone
: the currently active calculus method on each chart is assumed
See also
calculus_method()
andsage.manifolds.calculus_method.CalculusMethod.simplify()
for a control of the calculus method chart by chartEXAMPLES:
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
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological') >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2) >>> f = M.scalar_field((x+y)**Integer(2) + cos(x)**Integer(2)) >>> g = M.scalar_field(-x**Integer(2)-Integer(2)*x*y-y**Integer(2) + sin(x)**Integer(2)) >>> f.expr() (x + y)^2 + cos(x)^2 >>> g.expr() -x^2 - 2*x*y - y^2 + sin(x)^2 >>> s = f + g
M = Manifold(2, 'M', structure='topological') X.<x,y> = M.chart() f = M.scalar_field((x+y)^2 + cos(x)^2) g = M.scalar_field(-x^2-2*x*y-y^2 + sin(x)^2) f.expr() g.expr() s = f + g
The outcome is automatically simplified:
sage: s.expr() 1
>>> from sage.all import * >>> s.expr() 1
s.expr()
The simplification is performed thanks to the default simplifying function on chart
X
, which issimplify_chain_real()
in the present case (real manifold andSR
calculus):sage: X.calculus_method().simplify_function() is \ ....: sage.manifolds.utilities.simplify_chain_real True
>>> from sage.all import * >>> X.calculus_method().simplify_function() is sage.manifolds.utilities.simplify_chain_real True
X.calculus_method().simplify_function() is \ sage.manifolds.utilities.simplify_chain_real
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
>>> from sage.all import * >>> M.set_simplify_function(simplify) >>> X.calculus_method().simplify_function() is simplify True
M.set_simplify_function(simplify) X.calculus_method().simplify_function() is simplify
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
>>> from sage.all import * >>> s = f + g >>> s.expr() (x + y)^2 - x^2 - 2*x*y - y^2 + cos(x)^2 + sin(x)^2
s = f + g s.expr()
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
>>> from sage.all import * >>> def simpl_trig(a): ... return a.simplify_trig() >>> M.set_simplify_function(simpl_trig) >>> s = f + g >>> s.expr() 1
def simpl_trig(a): return a.simplify_trig() M.set_simplify_function(simpl_trig) s = f + g s.expr()
The default simplifying function is restored via:
sage: M.set_simplify_function('default')
>>> from sage.all import * >>> M.set_simplify_function('default')
M.set_simplify_function('default')
Then we are back to:
sage: X.calculus_method().simplify_function() is \ ....: sage.manifolds.utilities.simplify_chain_real True
>>> from sage.all import * >>> X.calculus_method().simplify_function() is sage.manifolds.utilities.simplify_chain_real True
X.calculus_method().simplify_function() is \ sage.manifolds.utilities.simplify_chain_real
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 thattrigsimp()
is a SymPy method only):sage: def simpl_trig_sympy(a): ....: return a.trigsimp() sage: M.set_simplify_function(simpl_trig_sympy, method='sympy')
>>> from sage.all import * >>> def simpl_trig_sympy(a): ... return a.trigsimp() >>> M.set_simplify_function(simpl_trig_sympy, method='sympy')
def simpl_trig_sympy(a): return a.trigsimp() 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
>>> from sage.all import * >>> M.set_calculus_method('sympy') >>> X.calculus_method().simplify_function() is simpl_trig_sympy True
M.set_calculus_method('sympy') X.calculus_method().simplify_function() is simpl_trig_sympy
We have then:
sage: s = f + g sage: s.expr() 1 sage: type(s.expr()) <class 'sympy.core.numbers.One'>
>>> from sage.all import * >>> s = f + g >>> s.expr() 1 >>> type(s.expr()) <class 'sympy.core.numbers.One'>
s = f + g s.expr() type(s.expr())
- start_index()[source]¶
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
>>> from sage.all import * >>> M = Manifold(Integer(3), 'M', structure='topological') >>> M.start_index() 0 >>> M = Manifold(Integer(3), 'M', structure='topological', start_index=Integer(1)) >>> M.start_index() 1
M = Manifold(3, 'M', structure='topological') M.start_index() M = Manifold(3, 'M', structure='topological', start_index=1) M.start_index()
- top_charts()[source]¶
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))]
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological') >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2) >>> U = M.open_subset('U', coord_def={X: x>Integer(0)}) >>> Y = U.chart(names=('u', 'v',)); (u, v,) = Y._first_ngens(2) >>> M.top_charts() [Chart (M, (x, y)), Chart (U, (u, v))]
M = Manifold(2, 'M', structure='topological') X.<x,y> = M.chart() U = M.open_subset('U', coord_def={X: x>0}) Y.<u,v> = U.chart() M.top_charts()
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))]
>>> from sage.all import * >>> M.atlas() [Chart (M, (x, y)), Chart (U, (x, y)), Chart (U, (u, v))]
M.atlas()
See also
atlas()
for the complete list of charts defined on the manifold.
- vector_bundle(rank, name, field='real', latex_name=None)[source]¶
Return a topological vector bundle over the given field with given rank over this topological manifold.
INPUT:
rank
– rank of the vector bundlename
– name given to the total spacefield
– (default:'real'
) topological field giving the vector space structure to the fiberslatex_name
– (optional) LaTeX name for the total space
OUTPUT:
a topological vector bundle as an instance of
TopologicalVectorBundle
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
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='top') >>> M.vector_bundle(Integer(2), 'E') Topological real vector bundle E -> M of rank 2 over the base space 2-dimensional topological manifold M
M = Manifold(2, 'M', structure='top') M.vector_bundle(2, 'E')
- zero_scalar_field()[source]¶
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
>>> from sage.all import * >>> M = Manifold(Integer(2), 'M', structure='topological') >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2) >>> f = M.zero_scalar_field() ; f Scalar field zero on the 2-dimensional topological manifold M >>> f.display() zero: M → ℝ (x, y) ↦ 0 >>> f.parent() Algebra of scalar fields on the 2-dimensional topological manifold M >>> f is M.scalar_field_algebra().zero() True
M = Manifold(2, 'M', structure='topological') X.<x,y> = M.chart() f = M.zero_scalar_field() ; f f.display() f.parent() f is M.scalar_field_algebra().zero()