{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 3-sphere: the round metric\n",
"\n",
"This notebook demonstrates some differential geometry capabilities of SageMath on the example of the 3-dimensional sphere, $\\mathbb{S}^3$. The corresponding tools have been developed within the [SageManifolds](https://sagemanifolds.obspm.fr) project.\n",
"\n",
"Click [here](https://raw.githubusercontent.com/sagemanifolds/SageManifolds/master/Notebooks/SM_sphere_S3_metric.ipynb) to download the notebook file (ipynb format). To run it, you must start SageMath with the Jupyter notebook, via the command `sage -n jupyter`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*NB:* a version of SageMath at least equal to 8.3 is required to run this notebook:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'SageMath version 9.0.beta1, Release Date: 2019-10-12'"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"version()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First we set up the notebook to display mathematical objects using LaTeX formatting:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"%display latex"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To increase the computational speed, we ask for demanding computations to be parallelly performed on 8 cores:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"Parallelism().set(nproc=8)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## $\\mathbb{S}^3$ as a 3-dimensional Riemannian manifold\n",
"\n",
"We start by declaring $\\mathbb{S}^3$ as a Riemannian manifold of dimension 3:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"S3 = Manifold(3, 'S^3', latex_name=r'\\mathbb{S}^3', structure='Riemannian', \n",
" start_index=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"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\\}$."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3-dimensional Riemannian manifold S^3\n"
]
}
],
"source": [
"print(S3)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"3-dimensional Riemannian manifold S^3"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"S3"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Coordinate charts on $\\mathbb{S}^3$\n",
"\n",
"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,\n",
"which we may call the *North pole* and the *South pole* respectively. Let us introduce the open subsets covered by these two charts: \n",
"$$ U := \\mathbb{S}^3\\setminus\\{N\\} $$ \n",
"$$ V := \\mathbb{S}^3\\setminus\\{S\\} $$"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Open subset U of the 3-dimensional Riemannian manifold S^3\n"
]
}
],
"source": [
"U = S3.open_subset('U') ; print(U)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Open subset V of the 3-dimensional Riemannian manifold S^3\n"
]
}
],
"source": [
"V = S3.open_subset('V') ; print(V)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We declare that $\\mathbb{S}^3 = U \\cup V$:"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"S3.declare_union(U, V)"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"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:"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Chart (U, (x, y, z))"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"stereoN. = U.chart()\n",
"stereoN"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"x: (-oo, +oo); y: (-oo, +oo); z: (-oo, +oo)"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"stereoN.coord_range()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Similarly, we introduce on $V$ the coordinates $(x',y',z')$ corresponding to the stereographic projection from the South pole onto the equatorial plane:"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Chart (V, (xp, yp, zp))"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"stereoS. = V.chart(\"xp:x' yp:y' zp:z'\")\n",
"stereoS"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"xp: (-oo, +oo); yp: (-oo, +oo); zp: (-oo, +oo)"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"stereoS.coord_range()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"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:"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"xp = x/(x^2 + y^2 + z^2)\n",
"yp = y/(x^2 + y^2 + z^2)\n",
"zp = z/(x^2 + y^2 + z^2)"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r2 = x^2+y^2+z^2\n",
"stereoN_to_S = stereoN.transition_map(stereoS, \n",
" (x/r2, y/r2, z/r2), \n",
" intersection_name='W',\n",
" restrictions1= x^2+y^2+z^2!=0, \n",
" restrictions2= xp^2+yp^2+zp^2!=0)\n",
"stereoN_to_S.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"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$.\n",
"\n",
"The inverse coordinate transformation is computed by means of the method `inverse()`:"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"x = xp/(xp^2 + yp^2 + zp^2)\n",
"y = yp/(xp^2 + yp^2 + zp^2)\n",
"z = zp/(xp^2 + yp^2 + zp^2)"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"stereoS_to_N = stereoN_to_S.inverse()\n",
"stereoS_to_N.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that the situation is of course perfectly symmetric regarding the coordinates $(x,y,z)$ and $(x',y',z')$.\n",
"\n",
"At this stage, the user's atlas has four charts:"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"[Chart (U, (x, y, z)),\n",
" Chart (V, (xp, yp, zp)),\n",
" Chart (W, (x, y, z)),\n",
" Chart (W, (xp, yp, zp))]"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"S3.atlas()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For future reference, we store $W=U\\cap V$ into a Python variable:"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Open subset W of the 3-dimensional Riemannian manifold S^3\n"
]
}
],
"source": [
"W = U.intersection(V)\n",
"print(W)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The North and South poles\n",
"\n",
"$N$ is the point of $V$ of stereographic coordinates $(x',y',z')=(0,0,0)$:"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Point N on the 3-dimensional Riemannian manifold S^3\n"
]
}
],
"source": [
"N = V((0,0,0), chart=stereoS, name='N')\n",
"print(N)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"while $S$ is the point of $U$ of stereographic coordinates $(x,y,z)=(0,0,0)$:"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Point S on the 3-dimensional Riemannian manifold S^3\n"
]
}
],
"source": [
"S = U((0,0,0), chart=stereoN, name='S')\n",
"print(S)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We have of course"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"True"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"all([N not in U, N in V, S in U, S not in V])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Embedding of $\\mathbb{S}^3$ into $\\mathbb{R}^4$\n",
"\n",
"Let us first declare $\\mathbb{R}^4$ as the 4-dimensional Euclidean space, denoting the Cartesian coordinates by\n",
"$(T,X,Y,Z)$:"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Chart (R^4, (T, X, Y, Z))"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"R4. = EuclideanSpace(name='R^4', latex_name=r'\\mathbb{R}^4', metric_name='h')\n",
"X4 = R4.cartesian_coordinates()\n",
"X4"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"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$:"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Phi: S^3 --> R^4\n",
"on U: (x, y, z) |--> (T, X, Y, Z) = (-(x^2 + y^2 + z^2 - 1)/(x^2 + y^2 + z^2 + 1), 2*x/(x^2 + y^2 + z^2 + 1), 2*y/(x^2 + y^2 + z^2 + 1), 2*z/(x^2 + y^2 + z^2 + 1))\n",
"on V: (xp, yp, zp) |--> (T, X, Y, Z) = ((xp^2 + yp^2 + zp^2 - 1)/(xp^2 + yp^2 + zp^2 + 1), 2*xp/(xp^2 + yp^2 + zp^2 + 1), 2*yp/(xp^2 + yp^2 + zp^2 + 1), 2*zp/(xp^2 + yp^2 + zp^2 + 1))"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"rp2 = xp^2 + yp^2 + zp^2\n",
"Phi = S3.diff_map(R4, {(stereoN, X4): \n",
" [(1-r2)/(r2+1), 2*x/(r2+1), \n",
" 2*y/(r2+1), 2*z/(r2+1)],\n",
" (stereoS, X4):\n",
" [(rp2-1)/(rp2+1), 2*xp/(rp2+1), \n",
" 2*yp/(rp2+1), 2*zp/(rp2+1)]},\n",
" name='Phi', latex_name=r'\\Phi')\n",
"Phi.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Hyperspherical coordinates\n",
"\n",
"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:"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Open subset A of the 3-dimensional Riemannian manifold S^3\n"
]
}
],
"source": [
"A = W.open_subset('A', coord_def={stereoN.restrict(W): (y!=0, x<0), \n",
" stereoS.restrict(W): (yp!=0, xp<0)})\n",
"print(A)"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Chart (A, (ch, th, ph))"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spher. = A.chart(r'ch:(0,pi):\\chi th:(0,pi):\\theta ph:(0,2*pi):\\phi')\n",
"spher"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"x = cos(ph)*sin(ch)*sin(th)/(cos(ch) + 1)\n",
"y = sin(ch)*sin(ph)*sin(th)/(cos(ch) + 1)\n",
"z = cos(th)*sin(ch)/(cos(ch) + 1)"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"den = 1 + cos(ch)\n",
"spher_to_stereoN = spher.transition_map(stereoN.restrict(A), \n",
" (sin(ch)*sin(th)*cos(ph)/den,\n",
" sin(ch)*sin(th)*sin(ph)/den,\n",
" sin(ch)*cos(th)/den))\n",
"spher_to_stereoN.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We also provide the inverse transition map by means of the method `set_inverse`, which (by default) performs a check that the provided formulas are indeed correct:"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Check of the inverse coordinate transformation:\n",
" ch == 2*arctan(sqrt(-cos(ch) + 1)/sqrt(cos(ch) + 1)) **failed**\n",
" th == arctan2(sqrt(-cos(ch) + 1)*sin(th)/sqrt(cos(ch) + 1), cos(th)*sin(ch)/(cos(ch) + 1)) **failed**\n",
" ph == pi - arctan2(sin(ch)*sin(ph)*sin(th)/(cos(ch) + 1), -cos(ph)*sin(ch)*sin(th)/(cos(ch) + 1)) **failed**\n",
" x == x *passed*\n",
" y == y *passed*\n",
" z == z *passed*\n",
"NB: a failed report can reflect a mere lack of simplification.\n"
]
}
],
"source": [
"spher_to_stereoN.set_inverse(2*atan(sqrt(x^2+y^2+z^2)),\n",
" atan2(sqrt(x^2+y^2), z),\n",
" atan2(-y, -x) + pi)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The check is passed, modulo some lack of trigonometric simplifications in the first three lines."
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"ch = 2*arctan(sqrt(x^2 + y^2 + z^2))\n",
"th = arctan2(sqrt(x^2 + y^2), z)\n",
"ph = pi + arctan2(-y, -x)"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spher_to_stereoN.inverse().display()"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"xp = (cos(ch) + 1)*cos(ph)*sin(th)/sin(ch)\n",
"yp = (cos(ch) + 1)*sin(ph)*sin(th)/sin(ch)\n",
"zp = (cos(ch) + 1)*cos(th)/sin(ch)"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spher_to_stereoS = stereoN_to_S.restrict(A) * spher_to_stereoN\n",
"spher_to_stereoS.display()"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"ch = 2*arctan(1/sqrt(xp^2 + yp^2 + zp^2))\n",
"th = arctan2(sqrt(xp^2 + yp^2)/(xp^2 + yp^2 + zp^2), zp/(xp^2 + yp^2 + zp^2))\n",
"ph = pi - arctan2(yp/(xp^2 + yp^2 + zp^2), -xp/(xp^2 + yp^2 + zp^2))"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"stereoS_to_spher = spher_to_stereoN.inverse() * stereoS_to_N.restrict(A)\n",
"stereoS_to_spher.display()"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Phi: S^3 --> R^4\n",
"on A: (x, y, z) |--> (T, X, Y, Z) = (-(x^2 + y^2 + z^2 - 1)/(x^2 + y^2 + z^2 + 1), 2*x/(x^2 + y^2 + z^2 + 1), 2*y/(x^2 + y^2 + z^2 + 1), 2*z/(x^2 + y^2 + z^2 + 1))"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Phi.display(stereoN.restrict(A), X4)"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Phi: S^3 --> R^4\n",
"on A: (ch, th, ph) |--> (T, X, Y, Z) = (cos(ch), cos(ph)*sin(ch)*sin(th), sin(ch)*sin(ph)*sin(th), cos(th)*sin(ch))"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Phi.display(spher, X4)"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Phi: S^3 --> R^4\n",
"on U: (x, y, z) |--> (T, X, Y, Z) = (-(x^2 + y^2 + z^2 - 1)/(x^2 + y^2 + z^2 + 1), 2*x/(x^2 + y^2 + z^2 + 1), 2*y/(x^2 + y^2 + z^2 + 1), 2*z/(x^2 + y^2 + z^2 + 1))\n",
"on V: (xp, yp, zp) |--> (T, X, Y, Z) = ((xp^2 + yp^2 + zp^2 - 1)/(xp^2 + yp^2 + zp^2 + 1), 2*xp/(xp^2 + yp^2 + zp^2 + 1), 2*yp/(xp^2 + yp^2 + zp^2 + 1), 2*zp/(xp^2 + yp^2 + zp^2 + 1))\n",
"on A: (ch, th, ph) |--> (T, X, Y, Z) = (cos(ch), cos(ph)*sin(ch)*sin(th), sin(ch)*sin(ph)*sin(th), cos(th)*sin(ch))"
]
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Phi.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Global left-invariant vector frame on $\\mathbb{S}^3$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The vector frames associated with the two stereographic charts are"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Coordinate frame (U, (d/dx,d/dy,d/dz))"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"frameN = stereoN.frame()\n",
"frameN"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Coordinate frame (V, (d/dxp,d/dyp,d/dzp))"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"frameS = stereoS.frame()\n",
"frameS"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"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 notebook\n",
"[3-sphere: vector fields and left-invariant parallelization](http://nbviewer.jupyter.org/github/sagemanifolds/SageManifolds/blob/master/Notebooks/SM_sphere_S3_vectors.ipynb). We first declare this vector frame on all $\\mathbb{S}^3$:"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Vector frame (S^3, (E_1,E_2,E_3))"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"E = S3.vector_frame('E', latex_symbol=r'\\varepsilon')\n",
"E"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"On $U$, we relate this frame to the stereographic coordinate frame, by means of the formulas obtained in the vector field notebook mentioned above:"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Vector frame (U, (E_1,E_2,E_3))"
]
},
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"E_U = E.restrict(U); E_U"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [],
"source": [
"E_U[1][frameN,:,stereoN] = \\\n",
" [(x^2-y^2-z^2+1)/2, x*y+z, x*z-y]\n",
"E_U[2][frameN,:,stereoN] = \\\n",
" [x*y-z, (1-x^2+y^2-z^2)/2, x+y*z] \n",
"E_U[3][frameN,:,stereoN] = \\\n",
" [x*z+y, y*z-x, (1-x^2-y^2+z^2)/2]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Similarly, on $V$, we relate the global frame with the stereographic coordinate frame from the South pole:"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Vector frame (V, (E_1,E_2,E_3))"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"E_V = E.restrict(V); E_V"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {},
"outputs": [],
"source": [
"E_V[1][frameS,:, stereoS] = \\\n",
" [(yp^2+zp^2-xp^2-1)/2, zp-xp*yp, -yp-xp*zp]\n",
"E_V[2][frameS,:, stereoS] = \\\n",
" [-zp-xp*yp, (xp^2-yp^2+zp^2-1)/2, xp-yp*zp]\n",
"E_V[3][frameS,:, stereoS] = \\\n",
" [yp-xp*zp, -xp-yp*zp, (xp^2+yp^2-zp^2-1)/2]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let us display the links between the various frames:"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"E_1 = (1/2*x^2 - 1/2*y^2 - 1/2*z^2 + 1/2) d/dx + (x*y + z) d/dy + (x*z - y) d/dz"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
""
],
"text/plain": [
"E_2 = (x*y - z) d/dx + (-1/2*x^2 + 1/2*y^2 - 1/2*z^2 + 1/2) d/dy + (y*z + x) d/dz"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
""
],
"text/plain": [
"E_3 = (x*z + y) d/dx + (y*z - x) d/dy + (-1/2*x^2 - 1/2*y^2 + 1/2*z^2 + 1/2) d/dz"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
" \n"
]
},
{
"data": {
"text/html": [
""
],
"text/plain": [
"E_1 = (-1/2*xp^2 + 1/2*yp^2 + 1/2*zp^2 - 1/2) d/dxp + (-xp*yp + zp) d/dyp + (-xp*zp - yp) d/dzp"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
""
],
"text/plain": [
"E_2 = (-xp*yp - zp) d/dxp + (1/2*xp^2 - 1/2*yp^2 + 1/2*zp^2 - 1/2) d/dyp + (-yp*zp + xp) d/dzp"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
""
],
"text/plain": [
"E_3 = (-xp*zp + yp) d/dxp + (-yp*zp - xp) d/dyp + (1/2*xp^2 + 1/2*yp^2 - 1/2*zp^2 - 1/2) d/dzp"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"for i in S3.irange():\n",
" show(E[i].display(frameN))\n",
"print(\" \")\n",
"for i in S3.irange():\n",
" show(E[i].display(frameS))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"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)$:"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {},
"outputs": [],
"source": [
"P = U.automorphism_field()\n",
"for i in S3.irange():\n",
" for j in S3.irange():\n",
" P[j,i] = E_U[i][j]"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"True"
]
},
"execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"all([E_U[i] == P(frameN[i]) for i in S3.irange()])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We add $P$ to the known changes of frame on $U$:"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {},
"outputs": [],
"source": [
"U.set_change_of_frame(frameN, E_U, P)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Similarly, on $V$, we introduce the operator $P$ such that $\\epsilon_i = P(\\partial/\\partial {x'}^i)$, with ${x'}^i=(x',y',z')$:"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {},
"outputs": [],
"source": [
"P = V.automorphism_field()\n",
"for i in S3.irange():\n",
" for j in S3.irange():\n",
" P[j,i] = E_V[i][j]"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"True"
]
},
"execution_count": 45,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"all([E_V[i] == P(frameS[i]) for i in S3.irange()])"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {},
"outputs": [],
"source": [
"V.set_change_of_frame(frameS, E_V, P)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Hopf coordinates"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"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\n",
"**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 notebook [3-sphere: charts, quaternions and Hopf fibration](http://nbviewer.jupyter.org/github/sagemanifolds/SageManifolds/blob/master/Notebooks/SM_sphere_S3_Hopf.ipynb): "
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Open subset B of the 3-dimensional Riemannian manifold S^3\n"
]
}
],
"source": [
"B = U.open_subset('B', coord_def={stereoN.restrict(U): \n",
" [x^2+y^2!=0, x^2+y^2+z^2!=1, \n",
" (1-x^2-y^2-z^2)*x-2*y*z!=0]})\n",
"print(B)"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Chart (B, (eta, alpha, beta))"
]
},
"execution_count": 48,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Hcoord. = B.chart(r\"eta:(0,pi/2):\\eta alpha:(0,2*pi):\\alpha beta:(0,2*pi):\\beta\")\n",
"Hcoord"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"x = cos(alpha + beta)*sin(eta)/(cos(eta)*sin(alpha) + 1)\n",
"y = sin(alpha + beta)*sin(eta)/(cos(eta)*sin(alpha) + 1)\n",
"z = cos(alpha)*cos(eta)/(cos(eta)*sin(alpha) + 1)"
]
},
"execution_count": 49,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Hcoord_to_stereoN = Hcoord.transition_map(\n",
" stereoN.restrict(U),\n",
" (sin(eta)*cos(alp+bet)/(1+cos(eta)*sin(alp)),\n",
" sin(eta)*sin(alp+bet)/(1+cos(eta)*sin(alp)),\n",
" cos(eta)*cos(alp)/(1+cos(eta)*sin(alp))))\n",
"Hcoord_to_stereoN.display()"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Check of the inverse coordinate transformation:\n",
" eta == arcsin((cos(eta)*sin(alpha) + 1)*sqrt(cos(eta) + 1)*sqrt(-cos(eta) + 1)/abs(cos(eta)*sin(alpha) + 1)) **failed**\n",
" alpha == pi - arctan2(2*cos(eta)*sin(alpha)/(cos(eta)*sin(alpha) + 1), -2*cos(alpha)*cos(eta)/(cos(eta)*sin(alpha) + 1)) **failed**\n",
" 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)) **failed**\n",
" x == x *passed*\n",
" y == y *passed*\n",
" z == z *passed*\n",
"NB: a failed report can reflect a mere lack of simplification.\n"
]
}
],
"source": [
"Hcoord_to_stereoN.set_inverse(asin(2*sqrt(x^2+y^2)/(1+x^2+y^2+z^2)),\n",
" atan2(x^2+y^2+z^2-1, -2*z) + pi,\n",
" atan2(-y,-x) - atan2(x^2+y^2+z^2-1, -2*z))"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"eta = arcsin(2*sqrt(x^2 + y^2)/(x^2 + y^2 + z^2 + 1))\n",
"alpha = pi + arctan2(x^2 + y^2 + z^2 - 1, -2*z)\n",
"beta = -arctan2(x^2 + y^2 + z^2 - 1, -2*z) + arctan2(-y, -x)"
]
},
"execution_count": 51,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Hcoord_to_stereoN.inverse().display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As explained in the notebook [3-sphere: vector fields and left-invariant parallelization](http://nbviewer.jupyter.org/github/sagemanifolds/SageManifolds/blob/master/Notebooks/SM_sphere_S3_vectors.ipynb), due to some lack of simplification, it's better to set the components of $\\varepsilon_1$ and $\\varepsilon_2$ by hand:"
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"E_1 = sin(2*alpha + beta) d/deta - cos(2*alpha + beta)*tan(eta) d/dalpha + cos(2*alpha + beta)/(cos(eta)*sin(eta)) d/dbeta"
]
},
"execution_count": 52,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"E_U[1].add_comp(Hcoord.frame())[1, Hcoord] = sin(2*alp+bet)\n",
"E_U[1].add_comp(Hcoord.frame())[2, Hcoord] = -cos(2*alp+bet) * tan(eta)\n",
"E_U[1].add_comp(Hcoord.frame())[3, Hcoord] = cos(2*alp+bet) / (cos(eta)*sin(eta))\n",
"E_U[1].display(Hcoord.frame(), Hcoord)"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"E_2 = -cos(2*alpha + beta) d/deta - sin(2*alpha + beta)*tan(eta) d/dalpha + sin(2*alpha + beta)/(cos(eta)*sin(eta)) d/dbeta"
]
},
"execution_count": 53,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"E_U[2].add_comp(Hcoord.frame())[1, Hcoord] = -cos(2*alp+bet)\n",
"E_U[2].add_comp(Hcoord.frame())[2, Hcoord] = -sin(2*alp+bet) * tan(eta)\n",
"E_U[2].add_comp(Hcoord.frame())[3, Hcoord] = sin(2*alp+bet) / (cos(eta)*sin(eta))\n",
"E_U[2].display(Hcoord.frame(), Hcoord)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"On the contrary, the components of $\\varepsilon_3$ are particularly simple:"
]
},
{
"cell_type": "code",
"execution_count": 54,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"E_3 = -d/dalpha"
]
},
"execution_count": 54,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"E_U[3].display(Hcoord.frame(), Hcoord)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Round metric on $\\mathbb{S}^3$\n",
"\n",
"The standard metric on $\\mathbb{S}^3$ is that induced by the Euclidean metric of $\\mathbb{R}^4$. The latter\n",
"is obtained by:"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"h = dT*dT + dX*dX + dY*dY + dZ*dZ"
]
},
"execution_count": 55,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"h = R4.metric()\n",
"h.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The metric $g$ on $\\mathbb{S}^3$ is computed as being the pullback of $h$ by the embedding $\\Phi$:"
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Riemannian metric g on the 3-dimensional Riemannian manifold S^3\n"
]
}
],
"source": [
"g = S3.metric()\n",
"g.set( Phi.pullback(h) )\n",
"print(g)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let us display $g$ in terms of the coordinate frame associated with the stereographic chart from the North pole $(U,(x,y,z))$:"
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"g = 4/(x^4 + y^4 + z^4 + 2*(x^2 + 1)*y^2 + 2*(x^2 + y^2 + 1)*z^2 + 2*x^2 + 1) dx*dx + 4/(x^4 + y^4 + z^4 + 2*(x^2 + 1)*y^2 + 2*(x^2 + y^2 + 1)*z^2 + 2*x^2 + 1) dy*dy + 4/(x^4 + y^4 + z^4 + 2*(x^2 + 1)*y^2 + 2*(x^2 + y^2 + 1)*z^2 + 2*x^2 + 1) dz*dz"
]
},
"execution_count": 57,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.display(frameN)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The components can be factored:"
]
},
{
"cell_type": "code",
"execution_count": 58,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"g = 4/(x^2 + y^2 + z^2 + 1)^2 dx*dx + 4/(x^2 + y^2 + z^2 + 1)^2 dy*dy + 4/(x^2 + y^2 + z^2 + 1)^2 dz*dz"
]
},
"execution_count": 58,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"for i in S3.irange():\n",
" g[frameN, i,i].factor()\n",
"g.display(frameN)"
]
},
{
"cell_type": "code",
"execution_count": 59,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"g = 4/(xp^4 + yp^4 + zp^4 + 2*(xp^2 + 1)*yp^2 + 2*(xp^2 + yp^2 + 1)*zp^2 + 2*xp^2 + 1) dxp*dxp + 4/(xp^4 + yp^4 + zp^4 + 2*(xp^2 + 1)*yp^2 + 2*(xp^2 + yp^2 + 1)*zp^2 + 2*xp^2 + 1) dyp*dyp + 4/(xp^4 + yp^4 + zp^4 + 2*(xp^2 + 1)*yp^2 + 2*(xp^2 + yp^2 + 1)*zp^2 + 2*xp^2 + 1) dzp*dzp"
]
},
"execution_count": 59,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.display(frameS)"
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"g = 4/(xp^2 + yp^2 + zp^2 + 1)^2 dxp*dxp + 4/(xp^2 + yp^2 + zp^2 + 1)^2 dyp*dyp + 4/(xp^2 + yp^2 + zp^2 + 1)^2 dzp*dzp"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"for i in S3.irange():\n",
" g[frameS, i,i].factor()\n",
"g.display(frameS)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Expression of the round metric in the global frame\n",
"\n",
"The expression of $g$ in terms of the global frame \n",
"$(\\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:"
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"g = E^1*E^1 + E^2*E^2 + E^3*E^3"
]
},
"execution_count": 61,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.display(E_U)"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"g = E^1*E^1 + E^2*E^2 + E^3*E^3"
]
},
"execution_count": 62,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.display(E_V)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We may then set the components globally:"
]
},
{
"cell_type": "code",
"execution_count": 63,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"g = E^1*E^1 + E^2*E^2 + E^3*E^3"
]
},
"execution_count": 63,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"for i in S3.irange():\n",
" g.add_comp(E)[i, i] = 1\n",
"g.display(E)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"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 \n",
"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}}$\n",
"in the notebook [3-sphere: vector fields and left-invariant parallelization](http://nbviewer.jupyter.org/github/sagemanifolds/SageManifolds/blob/master/Notebooks/SM_sphere_S3_vectors.ipynb)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Expression of the round metric in terms of the hyperspherical coordinates"
]
},
{
"cell_type": "code",
"execution_count": 64,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"g = dch*dch + sin(ch)^2 dth*dth + sin(ch)^2*sin(th)^2 dph*dph"
]
},
"execution_count": 64,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.display(spher.frame(), spher)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Expression of the round metric in terms of the Hopf coordinates"
]
},
{
"cell_type": "code",
"execution_count": 65,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"g = deta*deta + dalpha*dalpha + sin(eta)^2 dalpha*dbeta + sin(eta)^2 dbeta*dalpha + sin(eta)^2 dbeta*dbeta"
]
},
"execution_count": 65,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.display(Hcoord.frame(), Hcoord)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We note that the components of $g$ depend only on $\\eta$. This implies that the tori $\\eta=\\mathrm{const}$ are *flat* tori."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The Christoffel symbols"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is necessary for what follows (should be fixed in a future version):"
]
},
{
"cell_type": "code",
"execution_count": 66,
"metadata": {},
"outputs": [],
"source": [
"for chart in S3.top_charts():\n",
" g.restrict(chart.domain()).inverse()"
]
},
{
"cell_type": "code",
"execution_count": 67,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Gam^x_xx = -2*x/(x^2 + y^2 + z^2 + 1) \n",
"Gam^x_xy = -2*y/(x^2 + y^2 + z^2 + 1) \n",
"Gam^x_xz = -2*z/(x^2 + y^2 + z^2 + 1) \n",
"Gam^x_yy = 2*x/(x^2 + y^2 + z^2 + 1) \n",
"Gam^x_zz = 2*x/(x^2 + y^2 + z^2 + 1) \n",
"Gam^y_xx = 2*y/(x^2 + y^2 + z^2 + 1) \n",
"Gam^y_xy = -2*x/(x^2 + y^2 + z^2 + 1) \n",
"Gam^y_yy = -2*y/(x^2 + y^2 + z^2 + 1) \n",
"Gam^y_yz = -2*z/(x^2 + y^2 + z^2 + 1) \n",
"Gam^y_zz = 2*y/(x^2 + y^2 + z^2 + 1) \n",
"Gam^z_xx = 2*z/(x^2 + y^2 + z^2 + 1) \n",
"Gam^z_xz = -2*x/(x^2 + y^2 + z^2 + 1) \n",
"Gam^z_yy = 2*z/(x^2 + y^2 + z^2 + 1) \n",
"Gam^z_yz = -2*y/(x^2 + y^2 + z^2 + 1) \n",
"Gam^z_zz = -2*z/(x^2 + y^2 + z^2 + 1) "
]
},
"execution_count": 67,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.christoffel_symbols_display(stereoN)"
]
},
{
"cell_type": "code",
"execution_count": 68,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Gam^ch_th,th = -cos(ch)*sin(ch) \n",
"Gam^ch_ph,ph = -cos(ch)*sin(ch)*sin(th)^2 \n",
"Gam^th_ch,th = cos(ch)/sin(ch) \n",
"Gam^th_ph,ph = -cos(th)*sin(th) \n",
"Gam^ph_ch,ph = cos(ch)/sin(ch) \n",
"Gam^ph_th,ph = cos(th)/sin(th) "
]
},
"execution_count": 68,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.christoffel_symbols_display(spher)"
]
},
{
"cell_type": "code",
"execution_count": 69,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Gam^eta_alpha,beta = -cos(eta)*sin(eta) \n",
"Gam^eta_beta,beta = -cos(eta)*sin(eta) \n",
"Gam^alpha_eta,alpha = -sin(eta)/cos(eta) \n",
"Gam^beta_eta,alpha = -cos(eta)/(sin(eta)^3 - sin(eta)) \n",
"Gam^beta_eta,beta = cos(eta)/sin(eta) "
]
},
"execution_count": 69,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.christoffel_symbols_display(Hcoord)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The Riemann tensor"
]
},
{
"cell_type": "code",
"execution_count": 70,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Tensor field Riem(g) of type (1,3) on the 3-dimensional Riemannian manifold S^3\n"
]
}
],
"source": [
"Riem = g.riemann()\n",
"print(Riem)"
]
},
{
"cell_type": "code",
"execution_count": 71,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Riem(g)^x_yxy = 4/(x^4 + y^4 + z^4 + 2*(x^2 + 1)*y^2 + 2*(x^2 + y^2 + 1)*z^2 + 2*x^2 + 1) \n",
"Riem(g)^x_zxz = 4/(x^4 + y^4 + z^4 + 2*(x^2 + 1)*y^2 + 2*(x^2 + y^2 + 1)*z^2 + 2*x^2 + 1) \n",
"Riem(g)^y_xxy = -4/(x^4 + y^4 + z^4 + 2*(x^2 + 1)*y^2 + 2*(x^2 + y^2 + 1)*z^2 + 2*x^2 + 1) \n",
"Riem(g)^y_zyz = 4/(x^4 + y^4 + z^4 + 2*(x^2 + 1)*y^2 + 2*(x^2 + y^2 + 1)*z^2 + 2*x^2 + 1) \n",
"Riem(g)^z_xxz = -4/(x^4 + y^4 + z^4 + 2*(x^2 + 1)*y^2 + 2*(x^2 + y^2 + 1)*z^2 + 2*x^2 + 1) \n",
"Riem(g)^z_yyz = -4/(x^4 + y^4 + z^4 + 2*(x^2 + 1)*y^2 + 2*(x^2 + y^2 + 1)*z^2 + 2*x^2 + 1) "
]
},
"execution_count": 71,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Riem.display_comp(frameN, stereoN, only_nonredundant=True)"
]
},
{
"cell_type": "code",
"execution_count": 72,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Riem(g)^ch_th,ch,th = sin(ch)^2 \n",
"Riem(g)^ch_ph,ch,ph = sin(ch)^2*sin(th)^2 \n",
"Riem(g)^th_ch,ch,th = -1 \n",
"Riem(g)^th_ph,th,ph = sin(ch)^2*sin(th)^2 \n",
"Riem(g)^ph_ch,ch,ph = -1 \n",
"Riem(g)^ph_th,th,ph = -sin(ch)^2 "
]
},
"execution_count": 72,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Riem.display_comp(spher.frame(), spher, only_nonredundant=True)"
]
},
{
"cell_type": "code",
"execution_count": 73,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Riem(g)^eta_alpha,eta,alpha = 1 \n",
"Riem(g)^eta_alpha,eta,beta = sin(eta)^2 \n",
"Riem(g)^eta_beta,eta,alpha = sin(eta)^2 \n",
"Riem(g)^eta_beta,eta,beta = sin(eta)^2 \n",
"Riem(g)^alpha_eta,eta,alpha = -1 \n",
"Riem(g)^alpha_alpha,alpha,beta = sin(eta)^2 \n",
"Riem(g)^alpha_beta,alpha,beta = sin(eta)^2 \n",
"Riem(g)^beta_eta,eta,beta = -1 \n",
"Riem(g)^beta_alpha,alpha,beta = -1 \n",
"Riem(g)^beta_beta,alpha,beta = -sin(eta)^2 "
]
},
"execution_count": 73,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Riem.display_comp(Hcoord.frame(), Hcoord, only_nonredundant=True)"
]
},
{
"cell_type": "code",
"execution_count": 74,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Riem(g)^1_212 = 1 \n",
"Riem(g)^1_313 = 1 \n",
"Riem(g)^2_112 = -1 \n",
"Riem(g)^2_323 = 1 \n",
"Riem(g)^3_113 = -1 \n",
"Riem(g)^3_223 = -1 "
]
},
"execution_count": 74,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Riem.display_comp(E_U, stereoN, only_nonredundant=True)"
]
},
{
"cell_type": "code",
"execution_count": 75,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Riem(g) = E_1*E^2*E^1*E^2 - E_1*E^2*E^2*E^1 + E_1*E^3*E^1*E^3 - E_1*E^3*E^3*E^1 - E_2*E^1*E^1*E^2 + E_2*E^1*E^2*E^1 + E_2*E^3*E^2*E^3 - E_2*E^3*E^3*E^2 - E_3*E^1*E^1*E^3 + E_3*E^1*E^3*E^1 - E_3*E^2*E^2*E^3 + E_3*E^2*E^3*E^2"
]
},
"execution_count": 75,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Riem.display(E_U)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The Ricci tensor"
]
},
{
"cell_type": "code",
"execution_count": 76,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Field of symmetric bilinear forms Ric(g) on the 3-dimensional Riemannian manifold S^3\n"
]
}
],
"source": [
"Ric = g.ricci()\n",
"print(Ric)"
]
},
{
"cell_type": "code",
"execution_count": 77,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Ric(g) = 8/(x^4 + y^4 + z^4 + 2*(x^2 + 1)*y^2 + 2*(x^2 + y^2 + 1)*z^2 + 2*x^2 + 1) dx*dx + 8/(x^4 + y^4 + z^4 + 2*(x^2 + 1)*y^2 + 2*(x^2 + y^2 + 1)*z^2 + 2*x^2 + 1) dy*dy + 8/(x^4 + y^4 + z^4 + 2*(x^2 + 1)*y^2 + 2*(x^2 + y^2 + 1)*z^2 + 2*x^2 + 1) dz*dz"
]
},
"execution_count": 77,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Ric.display(frameN)"
]
},
{
"cell_type": "code",
"execution_count": 78,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"Ric(g) = 8/(x^2 + y^2 + z^2 + 1)^2 dx*dx + 8/(x^2 + y^2 + z^2 + 1)^2 dy*dy + 8/(x^2 + y^2 + z^2 + 1)^2 dz*dz"
]
},
"execution_count": 78,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"for i in S3.irange():\n",
" Ric[frameN, i,i].factor()\n",
"Ric.display(frameN)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We have $Ric(g) = 2 g$:"
]
},
{
"cell_type": "code",
"execution_count": 79,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"True"
]
},
"execution_count": 79,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Ric.restrict(U) == 2 * g.restrict(U)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The Ricci scalar"
]
},
{
"cell_type": "code",
"execution_count": 80,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Scalar field r(g) on the Open subset A of the 3-dimensional Riemannian manifold S^3\n"
]
}
],
"source": [
"R_A = g.restrict(A).ricci_scalar()\n",
"print(R_A)"
]
},
{
"cell_type": "code",
"execution_count": 81,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"r(g): A --> R\n",
" (x, y, z) |--> 6\n",
" (xp, yp, zp) |--> 6\n",
" (ch, th, ph) |--> 6"
]
},
"execution_count": 81,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"R_A.display()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We note that the Ricci scalar is constant, as for any maximally symmetric space."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## The volume 3-form (Levi-Civita tensor)\n",
"\n",
"We have"
]
},
{
"cell_type": "code",
"execution_count": 82,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3-form eps_g on the 3-dimensional Riemannian manifold S^3\n"
]
},
{
"data": {
"text/html": [
""
],
"text/plain": [
"eps_g = E^1/\\E^2/\\E^3"
]
},
"execution_count": 82,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"eps = S3.volume_form()\n",
"print(eps)\n",
"eps.display()"
]
},
{
"cell_type": "code",
"execution_count": 83,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Free module Omega^3(S^3) of 3-forms on the 3-dimensional Riemannian manifold S^3\n"
]
}
],
"source": [
"print(eps.parent())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Expression of the volume 3-form in terms of the stereographic coordinates"
]
},
{
"cell_type": "code",
"execution_count": 84,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"eps_g = 8/(x^6 + y^6 + z^6 + 3*(x^2 + 1)*y^4 + 3*(x^2 + y^2 + 1)*z^4 + 3*x^4 + 3*(x^4 + 2*x^2 + 1)*y^2 + 3*(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1)*z^2 + 3*x^2 + 1) dx/\\dy/\\dz"
]
},
"execution_count": 84,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"eps.display(frameN, stereoN)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The component $\\epsilon_{xyz}$ can be factored:"
]
},
{
"cell_type": "code",
"execution_count": 85,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"8/(x^6 + y^6 + z^6 + 3*(x^2 + 1)*y^4 + 3*(x^2 + y^2 + 1)*z^4 + 3*x^4 + 3*(x^4 + 2*x^2 + 1)*y^2 + 3*(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1)*z^2 + 3*x^2 + 1)"
]
},
"execution_count": 85,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"eps_xyz = eps[frameN, 1,2,3, stereoN]\n",
"eps_xyz"
]
},
{
"cell_type": "code",
"execution_count": 86,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"8/(x^2 + y^2 + z^2 + 1)^3"
]
},
"execution_count": 86,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"eps_xyz.factor()"
]
},
{
"cell_type": "code",
"execution_count": 87,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"eps_g = 8/(x^2 + y^2 + z^2 + 1)^3 dx/\\dy/\\dz"
]
},
"execution_count": 87,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"eps.display(frameN, stereoN)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "SageMath 9.0.beta1",
"language": "sage",
"name": "sagemath"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 1
}