This worksheet demonstrates a few capabilities of SageManifolds (version 1.0.2, as included in SageMath 8.0) on the example of the 3-dimensional sphere, $\mathbb{S}^3$.
Click here to download the worksheet file (ipynb format). To run it, you must start SageMath with the Jupyter notebook, via the command sage -n jupyter
NB: a version of SageMath at least equal to 8.0 is required to run this worksheet:
version()
'SageMath version 8.0, Release Date: 2017-07-21'
First we set up the notebook to display mathematical objects using LaTeX formatting:
%display latex
To increase the computational speed, we ask for demanding computations to be parallelly performed on 8 cores:
Parallelism().set(nproc=8)
We start by declaring $\mathbb{S}^3$ as a differentiable manifold of dimension 3 over $\mathbb{R}$:
S3 = Manifold(3, 'S^3', latex_name=r'\mathbb{S}^3', start_index=1)
The first argument, 3
, is the dimension of the manifold, while the second argument is the symbol used to label the manifold, with the LaTeX output specified by the argument latex_name
. The argument start_index
sets the index range to be used on the manifold for labelling components w.r.t. a basis or a frame: start_index=1
corresponds to $\{1,2,3\}$; the default value is start_index=0
, yielding to $\{0,1,2\}$.
print(S3)
3-dimensional differentiable manifold S^3
S3
The 3-sphere cannot be covered by a single chart. At least two charts are necessary, for instance the charts associated with the stereographic projections from two distinct points, $N$ and $S$ say,
which we may call the North pole and the South pole respectively. Let us introduce the open subsets covered by these two charts:
$$ U := \mathbb{S}^3\setminus\{N\} $$
$$ V := \mathbb{S}^3\setminus\{S\} $$
U = S3.open_subset('U') ; print(U)
Open subset U of the 3-dimensional differentiable manifold S^3
V = S3.open_subset('V') ; print(V)
Open subset V of the 3-dimensional differentiable manifold S^3
We declare that $\mathbb{S}^3 = U \cup V$:
S3.declare_union(U, V)
Then we introduce the stereographic chart on $U$, denoting by $(x,y,z)$ the coordinates resulting from the stereographic projection from the North pole onto the equatorial plane:
stereoN.<x,y,z> = U.chart()
stereoN
stereoN.coord_range()
Similarly, we introduce on $V$ the coordinates $(x',y',z')$ corresponding to the stereographic projection from the South pole onto the equatorial plane:
stereoS.<xp,yp,zp> = V.chart("xp:x' yp:y' zp:z'")
stereoS
stereoS.coord_range()
We have to specify the transition map between the charts stereoN
= $(U,(x,y,z))$ and stereoS
= $(V,(x',y',z'))$; it is given by the standard inversion formulas:
r2 = x^2+y^2+z^2
stereoN_to_S = stereoN.transition_map(stereoS,
(x/r2, y/r2, z/r2),
intersection_name='W',
restrictions1= x^2+y^2+z^2!=0,
restrictions2= xp^2+yp^2+zp^2!=0)
stereoN_to_S.display()
In the above declaration, 'W'
is the name given to the open subset where the two charts overlap: $W := U\cap V$, the condition $x^2+y^2+z^2\not=0$ defines $W$ as a subset of $U$, and the condition $x'^2+y'^2+z'^2\not=0$ defines $W$ as a subset of $V$.
The inverse coordinate transformation is computed by means of the method inverse()
:
stereoS_to_N = stereoN_to_S.inverse()
stereoS_to_N.display()
Note that the situation is of course perfectly symmetric regarding the coordinates $(x,y,z)$ and $(x',y',z')$.
At this stage, the user's atlas has four charts:
S3.atlas()
For future reference, we store $W=U\cap V$ into a Python variable:
W = U.intersection(V)
print(W)
Open subset W of the 3-dimensional differentiable manifold S^3
$N$ is the point of $V$ of stereographic coordinates $(x',y',z')=(0,0,0)$:
N = V((0,0,0), chart=stereoS, name='N')
print(N)
Point N on the 3-dimensional differentiable manifold S^3
while $S$ is the point of $U$ of stereographic coordinates $(x,y,z)=(0,0,0)$:
S = U((0,0,0), chart=stereoN, name='S')
print(S)
Point S on the 3-dimensional differentiable manifold S^3
We have of course
all([N not in U, N in V, S in U, S not in V])
Let us first declare $\mathbb{R}^4$ as a 4-dimensional manifold covered by a single chart (the so-called Cartesian coordinates):
R4 = Manifold(4, 'R^4', r'\mathbb{R}^4')
X4.<T,X,Y,Z> = R4.chart()
X4
The embedding of $\mathbb{S}^3$ into $\mathbb{R}^4$ is then defined by the standard formulas relating the stereographic coordinates to the ambient Cartesian ones when considering a stereographic projection from the point $(-1,0,0,0)$ to the equatorial plane $T=0$:
rp2 = xp^2 + yp^2 + zp^2
Phi = S3.diff_map(R4, {(stereoN, X4):
[(1-r2)/(r2+1), 2*x/(r2+1),
2*y/(r2+1), 2*z/(r2+1)],
(stereoS, X4):
[(rp2-1)/(rp2+1), 2*xp/(rp2+1),
2*yp/(rp2+1), 2*zp/(rp2+1)]},
name='Phi', latex_name=r'\Phi')
Phi.display()
The hyperspherical coordinates $(\chi, \theta, \phi)$ generalize the standard spherical coordinates $(\theta, \phi)$ on $\mathbb{S}^2$. They are defined on the open domain $A\subset W \subset \mathbb{S}^3$ that is the complement of the "origin meridian"; since the latter is defined by $y=0$ and $x\geq 0$, we declare:
A = W.open_subset('A', coord_def={stereoN.restrict(W): (y!=0, x<0),
stereoS.restrict(W): (yp!=0, xp<0)})
print(A)
Open subset A of the 3-dimensional differentiable manifold S^3
spher.<ch,th,ph> = A.chart(r'ch:(0,pi):\chi th:(0,pi):\theta ph:(0,2*pi):\phi')
spher
den = 1 + cos(ch)
spher_to_stereoN = spher.transition_map(stereoN.restrict(A),
(sin(ch)*sin(th)*cos(ph)/den,
sin(ch)*sin(th)*sin(ph)/den,
sin(ch)*cos(th)/den))
spher_to_stereoN.display()
spher_to_stereoN.set_inverse(2*atan(sqrt(x^2+y^2+z^2)),
atan2(sqrt(x^2+y^2), z),
atan2(-y, -x)+pi,
verbose=True)
Check of the inverse coordinate transformation: ch == 2*arctan(sqrt(-cos(ch) + 1)/sqrt(cos(ch) + 1)) th == arctan2(sqrt(-cos(ch) + 1)*sin(th)/sqrt(cos(ch) + 1), cos(th)*sin(ch)/(cos(ch) + 1)) ph == pi - arctan2(sin(ch)*sin(ph)*sin(th)/(cos(ch) + 1), -cos(ph)*sin(ch)*sin(th)/(cos(ch) + 1)) x == x y == y z == z
spher_to_stereoN.inverse().display()
spher_to_stereoS = stereoN_to_S.restrict(A) * spher_to_stereoN
spher_to_stereoS.display()
stereoS_to_spher = spher_to_stereoN.inverse() * stereoS_to_N.restrict(A)
stereoS_to_spher.display()
Phi.display(stereoN.restrict(A), X4)
Phi.display(spher, X4)
Phi.display()
The vector frames associated with the two stereographic charts are
frameN = stereoN.frame()
frameN
frameS = stereoS.frame()
frameS
None of these two frames cover entirely the 3-sphere, since $U$ and $V$ are strict subsets of $\mathbb{S}^3$. Now, as it is well known, $\mathbb{S}^3$ admits global vector frames, i.e. $\mathbb{S}^3$ is a parallelizable manifold. Among all the spheres, it shares this remarkable property with $\mathbb{S}^1$ and $\mathbb{S}^7$. We shall use a global vector frame $(\mathbb{S}^3, (\epsilon_1, \epsilon_2, \epsilon_3))$ associated with the Lie group structure of $\mathbb{S}^3$, namely the left-invariant vector frame constructed in the worksheet 3-sphere: vector fields and left-invariant parallelization. We first declare this vector frame on all $\mathbb{S}^3$:
E = S3.vector_frame('E', latex_symbol=r'\varepsilon')
E
On $U$, we relate this frame to the stereographic coordinate frame, by means of the formulas obtained in the vector field worksheet mentionned above:
E_U = E.restrict(U); E_U
E_U[1][frameN,:,stereoN] = \
[(x^2-y^2-z^2+1)/2, x*y+z, x*z-y]
E_U[2][frameN,:,stereoN] = \
[x*y-z, (1-x^2+y^2-z^2)/2, x+y*z]
E_U[3][frameN,:,stereoN] = \
[x*z+y, y*z-x, (1-x^2-y^2+z^2)/2]
Similarly, on $V$, we relate the global frame with the stereographic coordinate frame from the South pole:
E_V = E.restrict(V); E_V
E_V[1][frameS,:, stereoS] = \
[(yp^2+zp^2-xp^2-1)/2, zp-xp*yp, -yp-xp*zp]
E_V[2][frameS,:, stereoS] = \
[-zp-xp*yp, (xp^2-yp^2+zp^2-1)/2, xp-yp*zp]
E_V[3][frameS,:, stereoS] = \
[yp-xp*zp, -xp-yp*zp, (xp^2+yp^2-zp^2-1)/2]
Let us display the links between the various frames:
for i in S3.irange():
show(E[i].display(frameN))
print(" ")
for i in S3.irange():
show(E[i].display(frameS))
To complete the links, we introduce the change-of-frame operators: first the operator $P$ such that, on $U$, $\epsilon_i = P(\partial/\partial{x^i})$, with $x^i=(x,y,z)$:
P = U.automorphism_field()
for i in S3.irange():
for j in S3.irange():
P[j,i] = E_U[i][j]
all([E_U[i] == P(frameN[i]) for i in S3.irange()])
We add $P$ to the known changes of frame on $U$:
U.set_change_of_frame(frameN, E_U, P)
Similarly, on $V$, we introduce the operator $P$ such that $\epsilon_i = P(\partial/\partial {x'}^i)$, with ${x'}^i=(x',y',z')$:
P = V.automorphism_field()
for i in S3.irange():
for j in S3.irange():
P[j,i] = E_V[i][j]
all([E_V[i] == P(frameS[i]) for i in S3.irange()])
V.set_change_of_frame(frameS, E_V, P)
Despite there does not exist any coordinate chart associated to the global vector frame $(\mathbb{S}^3, (\epsilon_1, \epsilon_2, \epsilon_3))$, there exist a chart, called the Hopf chart, which has some link to it in the sense that some coordinate lines are integral curves of $\epsilon_3$. The Hopf coordinates have been introduced in the worksheet 3-sphere: charts, quaternions and Hopf fibration:
B = U.open_subset('B', coord_def={stereoN.restrict(U):
[x^2+y^2!=0, x^2+y^2+z^2!=1,
(1-x^2-y^2-z^2)*x-2*y*z!=0]})
print(B)
Open subset B of the 3-dimensional differentiable manifold S^3
Hcoord.<eta,alp,bet> = B.chart(r"eta:(0,pi/2):\eta alpha:(0,2*pi):\alpha beta:(0,2*pi):\beta")
Hcoord
Hcoord_to_stereoN = Hcoord.transition_map(
stereoN.restrict(U),
(sin(eta)*cos(alp+bet)/(1+cos(eta)*sin(alp)),
sin(eta)*sin(alp+bet)/(1+cos(eta)*sin(alp)),
cos(eta)*cos(alp)/(1+cos(eta)*sin(alp))))
Hcoord_to_stereoN.display()
Hcoord_to_stereoN.set_inverse(asin(2*sqrt(x^2+y^2)/(1+x^2+y^2+z^2)),
atan2(x^2+y^2+z^2-1, -2*z) + pi,
atan2(-y,-x) - atan2(x^2+y^2+z^2-1, -2*z),
verbose=True)
Check of the inverse coordinate transformation: eta == arcsin(sqrt(cos(eta) + 1)*sqrt(-cos(eta) + 1)) alpha == pi - arctan2(2*cos(eta)*sin(alpha)/(cos(eta)*sin(alpha) + 1), -2*cos(alpha)*cos(eta)/(cos(eta)*sin(alpha) + 1)) beta == arctan2(2*cos(eta)*sin(alpha)/(cos(eta)*sin(alpha) + 1), -2*cos(alpha)*cos(eta)/(cos(eta)*sin(alpha) + 1)) - arctan2((cos(beta)*sin(alpha) + cos(alpha)*sin(beta))*sin(eta)/(cos(eta)*sin(alpha) + 1), -(cos(alpha)*cos(beta) - sin(alpha)*sin(beta))*sin(eta)/(cos(eta)*sin(alpha) + 1)) x == x y == y z == z
Hcoord_to_stereoN.inverse().display()
As explained in the worksheet 3-sphere: vector fields and left-invariant parallelization, due to some lack of simplification, it's better to set the components of $\varepsilon_1$ and $\varepsilon_2$ by hand:
E_U[1].add_comp(Hcoord.frame())[1, Hcoord] = sin(2*alp+bet)
E_U[1].add_comp(Hcoord.frame())[2, Hcoord] = -cos(2*alp+bet) * tan(eta)
E_U[1].add_comp(Hcoord.frame())[3, Hcoord] = cos(2*alp+bet) / (cos(eta)*sin(eta))
E_U[1].display(Hcoord.frame(), Hcoord)
E_U[2].add_comp(Hcoord.frame())[1, Hcoord] = -cos(2*alp+bet)
E_U[2].add_comp(Hcoord.frame())[2, Hcoord] = -sin(2*alp+bet) * tan(eta)
E_U[2].add_comp(Hcoord.frame())[3, Hcoord] = sin(2*alp+bet) / (cos(eta)*sin(eta))
E_U[2].display(Hcoord.frame(), Hcoord)
On the contrary, the components of $\varepsilon_3$ are particularly simple:
E_U[3].display(Hcoord.frame(), Hcoord)
The standard metric on $\mathbb{S}^3$ is that induced by the Euclidean metric of $\mathbb{R}^4$. Let us start by defining the latter:
h = R4.metric('h')
h[0,0], h[1,1], h[2,2], h[3, 3] = 1, 1, 1, 1
h.display()
The metric $g$ on $\mathbb{S}^3$ is the pullback of $h$ by the embedding $\Phi$:
g = S3.metric('g')
g.set( Phi.pullback(h) )
print(g)
Riemannian metric g on the 3-dimensional differentiable manifold S^3
Let us display $g$ in terms of the coordinate frame associated with the stereographic chart from the North pole $(U,(x,y,z))$:
g.display(frameN)
The components can be factored:
for i in S3.irange():
g[frameN, i,i].factor()
g.display(frameN)
g.display(frameS)
for i in S3.irange():
g[frameS, i,i].factor()
g.display(frameS)
The expression of $g$ in terms of the global frame $(\varepsilon_1, \varepsilon_2, \varepsilon_3)$ is deduced from that w.r.t. the stereographic coordinates on the two domains $U$ and $V$, where the change-of-frame formulas are known:
g.display(E_U)
g.display(E_V)
We may then set the components globally:
for i in S3.irange():
g.add_comp(E)[i, i] = 1
g.display(E)
The above shows that the global frame $(\varepsilon_1, \varepsilon_2, \varepsilon_3)$ is orthonormal (w.r.t. to $g$), which is not surprising since this frame is induced by three vector fields of $\mathbb{R}^4$ which are clearly orthonormal for the Euclidean metric $h$, namely the three vector fields $E_{\mathbf{i}}$, $E_{\mathbf{j}}$ and $E_{\mathbf{k}}$ in the worksheet 3-sphere: vector fields and left-invariant parallelization.
g.display(spher.frame(), spher)
g.display(Hcoord.frame(), Hcoord)
We note that the components of $g$ depend only on $\eta$. This implies that the tori $\eta=\mathrm{const}$ are flat tori.
This is necessary for what follows (should be fixed in a future version):
for chart in S3.top_charts():
g.restrict(chart.domain()).inverse()
g.christoffel_symbols_display(stereoN)
g.christoffel_symbols_display(spher)
g.christoffel_symbols_display(Hcoord)
Riem = g.riemann()
print(Riem)
Tensor field Riem(g) of type (1,3) on the 3-dimensional differentiable manifold S^3
Riem.display_comp(frameN, stereoN, only_nonredundant=True)
Riem.display_comp(spher.frame(), spher, only_nonredundant=True)
Riem.display_comp(Hcoord.frame(), Hcoord, only_nonredundant=True)
Riem.display_comp(E_U, stereoN, only_nonredundant=True)
Riem.display(E_U)
Ric = g.ricci()
print(Ric)
Field of symmetric bilinear forms Ric(g) on the 3-dimensional differentiable manifold S^3
Ric.display(frameN)
for i in S3.irange():
Ric[frameN, i,i].factor()
Ric.display(frameN)
We have $Ric(g) = 2 g$:
Ric.restrict(U) == 2 * g.restrict(U)
R_A = g.restrict(A).ricci_scalar()
print(R_A)
Scalar field r(g) on the Open subset A of the 3-dimensional differentiable manifold S^3
R_A.display()
We note that the Ricci scalar is constant, as for any maximally symmetric space.
We have
eps = g.volume_form()
print(eps)
eps.display()
3-form eps_g on the 3-dimensional differentiable manifold S^3
print(eps.parent())
Free module /\^3(S^3) of 3-forms on the 3-dimensional differentiable manifold S^3
eps.display(frameN, stereoN)
The component $\epsilon_{xyz}$ can be factored:
eps_xyz = eps[frameN, 1,2,3, stereoN]
eps_xyz
eps_xyz.factor()
eps.display(frameN, stereoN)