{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 3-sphere: charts, quaternions and Hopf fibration\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_Hopf.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 7.5 is required to run this notebook:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'SageMath version 9.2.beta6, Release Date: 2020-07-25'"
]
},
"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": [
"and we initialize a time counter for benchmarking:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"import time\n",
"comput_time0 = time.perf_counter()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To increase the computational speed, we ask for demanding computations to be parallelly performed on 8 threads:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"Parallelism().set(nproc=8)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## $\\mathbb{S}^3$ as a 3-dimensional differentiable manifold\n",
"\n",
"We start by declaring $\\mathbb{S}^3$ as a differentiable manifold of dimension 3 over $\\mathbb{R}$:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"S3 = Manifold(3, 'S^3', latex_name=r'\\mathbb{S}^3', 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": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3-dimensional differentiable manifold S^3\n"
]
}
],
"source": [
"print(S3)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/latex": [
"\\begin{math}\n",
"\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\mathbb{S}^3\n",
"\\end{math}"
],
"text/plain": [
"3-dimensional differentiable manifold S^3"
]
},
"execution_count": 7,
"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": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Open subset U of the 3-dimensional differentiable manifold S^3\n"
]
}
],
"source": [
"U = S3.open_subset('U') ; print(U)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Open subset V of the 3-dimensional differentiable 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": 10,
"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": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/latex": [
"\\begin{math}\n",
"\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\left(U,(x, y, z)\\right)\n",
"\\end{math}"
],
"text/plain": [
"Chart (U, (x, y, z))"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"stereoN. = U.chart()\n",
"stereoN"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/latex": [
"\\begin{math}\n",
"\\newcommand{\\Bold}[1]{\\mathbf{#1}}x :\\ \\left( -\\infty, +\\infty \\right) ;\\quad y :\\ \\left( -\\infty, +\\infty \\right) ;\\quad z :\\ \\left( -\\infty, +\\infty \\right)\n",
"\\end{math}"
],
"text/plain": [
"x: (-oo, +oo); y: (-oo, +oo); z: (-oo, +oo)"
]
},
"execution_count": 12,
"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": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/latex": [
"\\begin{math}\n",
"\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\left(V,({x'}, {y'}, {z'})\\right)\n",
"\\end{math}"
],
"text/plain": [
"Chart (V, (xp, yp, zp))"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"stereoS. = V.chart(\"xp:x' yp:y' zp:z'\")\n",
"stereoS"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/latex": [
"\\begin{math}\n",
"\\newcommand{\\Bold}[1]{\\mathbf{#1}}{x'} :\\ \\left( -\\infty, +\\infty \\right) ;\\quad {y'} :\\ \\left( -\\infty, +\\infty \\right) ;\\quad {z'} :\\ \\left( -\\infty, +\\infty \\right)\n",
"\\end{math}"
],
"text/plain": [
"xp: (-oo, +oo); yp: (-oo, +oo); zp: (-oo, +oo)"
]
},
"execution_count": 14,
"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": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/latex": [
"\\begin{math}\n",
"\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\left\\{\\begin{array}{lcl} {x'} & = & \\frac{x}{x^{2} + y^{2} + z^{2}} \\\\ {y'} & = & \\frac{y}{x^{2} + y^{2} + z^{2}} \\\\ {z'} & = & \\frac{z}{x^{2} + y^{2} + z^{2}} \\end{array}\\right.\n",
"\\end{math}"
],
"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": 15,
"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": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/latex": [
"\\begin{math}\n",
"\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\left\\{\\begin{array}{lcl} x & = & \\frac{{x'}}{{x'}^{2} + {y'}^{2} + {z'}^{2}} \\\\ y & = & \\frac{{y'}}{{x'}^{2} + {y'}^{2} + {z'}^{2}} \\\\ z & = & \\frac{{z'}}{{x'}^{2} + {y'}^{2} + {z'}^{2}} \\end{array}\\right.\n",
"\\end{math}"
],
"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": 16,
"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": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/latex": [
"\\begin{math}\n",
"\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\left[\\left(U,(x, y, z)\\right), \\left(V,({x'}, {y'}, {z'})\\right), \\left(W,(x, y, z)\\right), \\left(W,({x'}, {y'}, {z'})\\right)\\right]\n",
"\\end{math}"
],
"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": 17,
"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": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Open subset W of the 3-dimensional differentiable 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": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Point N on the 3-dimensional differentiable 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": 20,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Point S on the 3-dimensional differentiable 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": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/latex": [
"\\begin{math}\n",
"\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\mathrm{True}\n",
"\\end{math}"
],
"text/plain": [
"True"
]
},
"execution_count": 21,
"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 a 4-dimensional manifold covered by a single chart (the so-called **Cartesian coordinates**):"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/latex": [
"\\begin{math}\n",
"\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\left(\\mathbb{R}^4,(T, X, Y, Z)\\right)\n",
"\\end{math}"
],
"text/plain": [
"Chart (R^4, (T, X, Y, Z))"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"R4 = Manifold(4, 'R^4', r'\\mathbb{R}^4')\n",
"X4. = R4.chart()\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": 23,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/latex": [
"\\begin{math}\n",
"\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\begin{array}{llcl} \\Phi:& \\mathbb{S}^3 & \\longrightarrow & \\mathbb{R}^4 \\\\ \\mbox{on}\\ U : & \\left(x, y, z\\right) & \\longmapsto & \\left(T, X, Y, Z\\right) = \\left(-\\frac{x^{2} + y^{2} + z^{2} - 1}{x^{2} + y^{2} + z^{2} + 1}, \\frac{2 \\, x}{x^{2} + y^{2} + z^{2} + 1}, \\frac{2 \\, y}{x^{2} + y^{2} + z^{2} + 1}, \\frac{2 \\, z}{x^{2} + y^{2} + z^{2} + 1}\\right) \\\\ \\mbox{on}\\ V : & \\left({x'}, {y'}, {z'}\\right) & \\longmapsto & \\left(T, X, Y, Z\\right) = \\left(\\frac{{x'}^{2} + {y'}^{2} + {z'}^{2} - 1}{{x'}^{2} + {y'}^{2} + {z'}^{2} + 1}, \\frac{2 \\, {x'}}{{x'}^{2} + {y'}^{2} + {z'}^{2} + 1}, \\frac{2 \\, {y'}}{{x'}^{2} + {y'}^{2} + {z'}^{2} + 1}, \\frac{2 \\, {z'}}{{x'}^{2} + {y'}^{2} + {z'}^{2} + 1}\\right) \\end{array}\n",
"\\end{math}"
],
"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": 23,
"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": [
"From this choice of stereographic projection, the \"North\" pole is actually the point of coordinates $(-1,0,0,0)$ in $\\mathbb{R}^4$:"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/latex": [
"\\begin{math}\n",
"\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\left(-1, 0, 0, 0\\right)\n",
"\\end{math}"
],
"text/plain": [
"(-1, 0, 0, 0)"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X4(Phi(N))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"while the \"South\" pole is the point of coordinates $(1,0,0,0)$:"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/latex": [
"\\begin{math}\n",
"\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\left(1, 0, 0, 0\\right)\n",
"\\end{math}"
],
"text/plain": [
"(1, 0, 0, 0)"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X4(Phi(S))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We may use the embedding $\\Phi$ to plot the stereographic coordinate grid in terms of the $\\mathbb{R}^4$'s Cartesian coordinates: "
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"scrolled": false
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"