{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Manifold tutorial\n", "\n", "This notebook provides a short introduction to differentiable manifolds in SageMath. The tools described below have been implemented through the [SageManifolds](https://sagemanifolds.obspm.fr) project.\n", "\n", "If you are new to SageMath, you may first take a look at this [first contact tutorial](https://nbviewer.org/github/egourgoulhon/SageMathTour/blob/master/Notebooks/first_contact.ipynb). " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This notebook is valid for version 9.2 or higher of SageMath:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'SageMath version 10.5, Release Date: 2024-12-04'" ] }, "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 rendering:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "%display latex" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Defining a manifold\n", "\n", "As an example let us define a differentiable manifold of dimension 3 over $\\mathbb{R}$:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "M = Manifold(3, 'M', latex_name=r'\\mathcal{M}', start_index=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- The first argument, `3`, is the manifold dimension; it can be any\n", " positive integer.\n", "- The second argument, `'M'`, is a string defining the manifold's name; it may be \n", " different from the symbol set on the left-hand side of the = sign (here `M`): the latter\n", " stands for the Python variable that refers to the manifold object in the computer \n", " memory, while the string `'M'` is the mathematical symbol chosen for the manifold.\n", "- The optional argument `latex_name=r'\\mathcal{M}'` sets the LaTeX\n", " symbol to display the manifold. Note the letter 'r' in front on the first quote: \n", " it indicates that the string is a *raw* one, so that the backslash character \n", " in `\\mathcal` is considered as an ordinary character (otherwise, the backslash is \n", " used to escape some special characters). If the argument `latex_name` is not \n", " provided by the user, it is set to the string used as the second argument (here `'M'`)\n", "- The optional argument `start_index=1` defines the range of indices to be used for \n", " tensor components on the manifold: setting it to 1 means that indices will range \n", " in $\\{1,2,3\\}$. The default value is `start_index=0`.\n", "\n", "Note that the default base field is $\\mathbb{R}$. If we would have used the optional\n", "argument `field='complex'`, we would have defined a manifold over $\\mathbb{C}$. See the\n", "[list of all options](http://doc.sagemath.org/html/en/reference/manifolds/sage/manifolds/manifold.html#sage.manifolds.manifold.Manifold) for more details. \n", "\n", "If we ask for `M`, it is displayed via its LaTeX symbol:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\mathcal{M}\\)" ], "text/latex": [ "$\\displaystyle \\mathcal{M}$" ], "text/plain": [ "3-dimensional differentiable manifold M" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "M" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we use the function `print()` instead, we get a short description of the object:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3-dimensional differentiable manifold M\n" ] } ], "source": [ "print(M)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Via the function `type()`, we get the type of the Python object corresponding to M (here the Python class `DifferentiableManifold_with_category`):" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "print(type(M))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We may also ask for the category of `M` and see that it is the category of smooth manifolds over $\\mathbb{R}$:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\newcommand{\\Bold}[1]{\\mathbf{#1}}\\mathbf{Smooth}_{\\Bold{R}}\\)" ], "text/latex": [ "$\\displaystyle \\newcommand{\\Bold}[1]{\\mathbf{#1}}\\mathbf{Smooth}_{\\Bold{R}}$" ], "text/plain": [ "Category of smooth manifolds over Real Field with 53 bits of precision" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "category(M)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The indices on the manifold are generated by the method `irange()`, to be used in loops:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left[1, 2, 3\\right]\\)" ], "text/latex": [ "$\\displaystyle \\left[1, 2, 3\\right]$" ], "text/plain": [ "[1, 2, 3]" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[i for i in M.irange()]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If the parameter `start_index` had not been specified, the default range of the indices would have been $\\{0,1,2\\}$ instead:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left[0, 1, 2\\right]\\)" ], "text/latex": [ "$\\displaystyle \\left[0, 1, 2\\right]$" ], "text/plain": [ "[0, 1, 2]" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "M0 = Manifold(3, 'M', latex_name=r'\\mathcal{M}')\n", "[i for i in M0.irange()]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Defining a chart on the manifold\n", "\n", "Let us assume that the manifold $\\mathcal{M}$ can be covered by a single chart (other cases are discussed below); the chart is declared as follows:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "X. = M.chart()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The writing `.` in the left-hand side means that the Python variables `x`, `y` and `z` are set to the three coordinates of the chart. This allows one to refer subsequently to the coordinates by their names.\n", "\n", "In this example, the function `chart()` has no arguments, which implies that the coordinate symbols will be `x`, `y` and `z` (i.e. exactly the characters set in the `<...>` operator) and that each coordinate range is $(-\\infty,+\\infty)$. For other cases, an argument must be passed to `chart()`  to specify the coordinate symbols and range, as well as the LaTeX symbol of a coordinate if the latter is different from the coordinate name (an example will be provided below)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The chart is displayed as a pair formed by the open set covered by it (here the whole manifold) and the coordinates:

" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Chart (M, (x, y, z))\n" ] } ], "source": [ "print(X)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left(\\mathcal{M},(x, y, z)\\right)\\)" ], "text/latex": [ "$\\displaystyle \\left(\\mathcal{M},(x, y, z)\\right)$" ], "text/plain": [ "Chart (M, (x, y, z))" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The coordinates can be accessed individually, by means of their indices, following the convention defined by `start_index=1` in the manifold's definition:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle x\\)" ], "text/latex": [ "$\\displaystyle x$" ], "text/plain": [ "x" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X[1]" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle y\\)" ], "text/latex": [ "$\\displaystyle y$" ], "text/plain": [ "y" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X[2]" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle z\\)" ], "text/latex": [ "$\\displaystyle z$" ], "text/plain": [ "z" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X[3]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The full set of coordinates is obtained by means of the operator `[:]`:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left(x, y, z\\right)\\)" ], "text/latex": [ "$\\displaystyle \\left(x, y, z\\right)$" ], "text/plain": [ "(x, y, z)" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X[:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Thanks to the operator `` used in the chart declaration, each coordinate can be accessed directly via its name:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\mathrm{True}\\)" ], "text/latex": [ "$\\displaystyle \\mathrm{True}$" ], "text/plain": [ "True" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z is X[3]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Coordinates are SageMath symbolic expressions:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\verb|<class|\\verb| |\\verb|'sage.symbolic.expression.Expression'>|\\)" ], "text/latex": [ "$\\displaystyle \\verb||$" ], "text/plain": [ "" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(z)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Functions of the chart coordinates\n", "\n", "Real-valued functions of the chart coordinates (mathematically speaking, *functions defined on the chart codomain*) are generated via the method `function()` acting on the chart:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle z^{3} + y^{2} + x\\)" ], "text/latex": [ "$\\displaystyle z^{3} + y^{2} + x$" ], "text/plain": [ "z^3 + y^2 + x" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = X.function(x+y^2+z^3)\n", "f" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left(x, y, z\\right) \\mapsto z^{3} + y^{2} + x\\)" ], "text/latex": [ "$\\displaystyle \\left(x, y, z\\right) \\mapsto z^{3} + y^{2} + x$" ], "text/plain": [ "(x, y, z) ↦ z^3 + y^2 + x" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.display()" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle 32\\)" ], "text/latex": [ "$\\displaystyle 32$" ], "text/plain": [ "32" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f(1,2,3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "They belong to the class `ChartFunction` (actually the subclass `𝙲𝚑𝚊𝚛𝚝𝙵𝚞𝚗𝚌𝚝𝚒𝚘𝚗𝚁𝚒𝚗𝚐_𝚠𝚒𝚝h_𝚌𝚊𝚝𝚎𝚐𝚘𝚛𝚢.𝚎𝚕𝚎𝚖𝚎𝚗t_𝚌𝚕𝚊𝚜𝚜`):" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "print(type(f))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and differ from SageMath standard symbolic functions by automatic simplifications in all operations. For instance, adding the two symbolic functions" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "f0(x,y,z) = cos(x)^2; g0(x,y,z) = sin(x)^2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "results in" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left( x, y, z \\right) \\ {\\mapsto} \\ \\cos\\left(x\\right)^{2} + \\sin\\left(x\\right)^{2}\\)" ], "text/latex": [ "$\\displaystyle \\left( x, y, z \\right) \\ {\\mapsto} \\ \\cos\\left(x\\right)^{2} + \\sin\\left(x\\right)^{2}$" ], "text/plain": [ "(x, y, z) |--> cos(x)^2 + sin(x)^2" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f0 + g0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "while the sum of the corresponding functions in the class `ChartFunction` is automatically simplified:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle 1\\)" ], "text/latex": [ "$\\displaystyle 1$" ], "text/plain": [ "1" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1 = X.function(cos(x)^2); g1 = X.function(sin(x)^2)\n", "f1 + g1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To get the same output with symbolic functions, one has to invoke the method `simplify_trig()`:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left( x, y, z \\right) \\ {\\mapsto} \\ 1\\)" ], "text/latex": [ "$\\displaystyle \\left( x, y, z \\right) \\ {\\mapsto} \\ 1$" ], "text/plain": [ "(x, y, z) |--> 1" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(f0 + g0).simplify_trig()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another difference regards the display; if we ask for the symbolic function `f0`, we get" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left( x, y, z \\right) \\ {\\mapsto} \\ \\cos\\left(x\\right)^{2}\\)" ], "text/latex": [ "$\\displaystyle \\left( x, y, z \\right) \\ {\\mapsto} \\ \\cos\\left(x\\right)^{2}$" ], "text/plain": [ "(x, y, z) |--> cos(x)^2" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "while if we ask for the chart function `f1`, we get only the coordinate expression:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\cos\\left(x\\right)^{2}\\)" ], "text/latex": [ "$\\displaystyle \\cos\\left(x\\right)^{2}$" ], "text/plain": [ "cos(x)^2" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To get an output similar to that of `f0`, one should call the method `display()`:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left(x, y, z\\right) \\mapsto \\cos\\left(x\\right)^{2}\\)" ], "text/latex": [ "$\\displaystyle \\left(x, y, z\\right) \\mapsto \\cos\\left(x\\right)^{2}$" ], "text/plain": [ "(x, y, z) ↦ cos(x)^2" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the method `expr()` returns the underlying symbolic expression:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\cos\\left(x\\right)^{2}\\)" ], "text/latex": [ "$\\displaystyle \\cos\\left(x\\right)^{2}$" ], "text/plain": [ "cos(x)^2" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1.expr()" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "print(type(f1.expr()))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Introducing a second chart on the manifold\n", "\n", "Let us first consider an open subset of $\\mathcal{M}$, for instance the complement $U$ of the region defined by $\\{y=0, x\\geq 0\\}$ (note that `(y!=0, x<0)` stands for $y\\not=0$ OR $x<0$; the condition $y\\not=0$ AND $x<0$ would have been written `[y!=0, x<0]` instead):" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "U = M.open_subset('U', coord_def={X: (y!=0, x<0)})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us call `X_U` the restriction of the chart `X` to the open subset $U$:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left(U,(x, y, z)\\right)\\)" ], "text/latex": [ "$\\displaystyle \\left(U,(x, y, z)\\right)$" ], "text/plain": [ "Chart (U, (x, y, z))" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X_U = X.restrict(U)\n", "X_U" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

We introduce another chart on $U$, with spherical-type coordinates $(r,\\theta,\\phi)$:

" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left(U,(r, {\\theta}, {\\phi})\\right)\\)" ], "text/latex": [ "$\\displaystyle \\left(U,(r, {\\theta}, {\\phi})\\right)$" ], "text/plain": [ "Chart (U, (r, th, ph))" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Y. = U.chart(r'r:(0,+oo) th:(0,pi):\\theta ph:(0,2*pi):\\phi')\n", "Y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The method `chart()` is now used with an argument; it is a string, which contains specific LaTeX symbols, hence the prefix 'r' to it (for *raw* string). It also contains the coordinate ranges, since they are different from the default value, which is $(-\\infty, +\\infty)$. For a given coordinate, the various fields are separated by the character ':' and a space character separates the coordinates. Note that for the coordinate $r$, there are only two fields, since the LaTeX symbol has not to be specified. The LaTeX symbols are used for the outputs:" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left({\\theta}, {\\phi}\\right)\\)" ], "text/latex": [ "$\\displaystyle \\left({\\theta}, {\\phi}\\right)$" ], "text/plain": [ "(th, ph)" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "th, ph" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left({\\theta}, {\\phi}\\right)\\)" ], "text/latex": [ "$\\displaystyle \\left({\\theta}, {\\phi}\\right)$" ], "text/plain": [ "(th, ph)" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Y[2], Y[3]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The declared coordinate ranges are now known to Sage, as we may check by means of the command `assumptions()`:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left[\\verb|x|\\verb| |\\verb|is|\\verb| |\\verb|real|, \\verb|y|\\verb| |\\verb|is|\\verb| |\\verb|real|, \\verb|z|\\verb| |\\verb|is|\\verb| |\\verb|real|, \\verb|r|\\verb| |\\verb|is|\\verb| |\\verb|real|, r > 0, \\verb|th|\\verb| |\\verb|is|\\verb| |\\verb|real|, {\\theta} > 0, {\\theta} < \\pi, \\verb|ph|\\verb| |\\verb|is|\\verb| |\\verb|real|, {\\phi} > 0, {\\phi} < 2 \\, \\pi\\right]\\)" ], "text/latex": [ "$\\displaystyle \\left[\\verb|x|\\verb| |\\verb|is|\\verb| |\\verb|real|, \\verb|y|\\verb| |\\verb|is|\\verb| |\\verb|real|, \\verb|z|\\verb| |\\verb|is|\\verb| |\\verb|real|, \\verb|r|\\verb| |\\verb|is|\\verb| |\\verb|real|, r > 0, \\verb|th|\\verb| |\\verb|is|\\verb| |\\verb|real|, {\\theta} > 0, {\\theta} < \\pi, \\verb|ph|\\verb| |\\verb|is|\\verb| |\\verb|real|, {\\phi} > 0, {\\phi} < 2 \\, \\pi\\right]$" ], "text/plain": [ "[x is real,\n", " y is real,\n", " z is real,\n", " r is real,\n", " r > 0,\n", " th is real,\n", " th > 0,\n", " th < pi,\n", " ph is real,\n", " ph > 0,\n", " ph < 2*pi]" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "assumptions()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

They are used in simplifications:

" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle r\\)" ], "text/latex": [ "$\\displaystyle r$" ], "text/plain": [ "r" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simplify(abs(r))" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle {\\left| x \\right|}\\)" ], "text/latex": [ "$\\displaystyle {\\left| x \\right|}$" ], "text/plain": [ "abs(x)" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simplify(abs(x)) # no simplification occurs since x can take any value in R" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "After having been declared, the chart `Y` can be fully specified by its relation to the chart `X_U`, via a transition map:" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left(U,(r, {\\theta}, {\\phi})\\right) \\rightarrow \\left(U,(x, y, z)\\right)\\)" ], "text/latex": [ "$\\displaystyle \\left(U,(r, {\\theta}, {\\phi})\\right) \\rightarrow \\left(U,(x, y, z)\\right)$" ], "text/plain": [ "Change of coordinates from Chart (U, (r, th, ph)) to Chart (U, (x, y, z))" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "transit_Y_to_X = Y.transition_map(X_U, [r*sin(th)*cos(ph), r*sin(th)*sin(ph), \n", " r*cos(th)])\n", "transit_Y_to_X" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left\\{\\begin{array}{lcl} x & = & r \\cos\\left({\\phi}\\right) \\sin\\left({\\theta}\\right) \\\\ y & = & r \\sin\\left({\\phi}\\right) \\sin\\left({\\theta}\\right) \\\\ z & = & r \\cos\\left({\\theta}\\right) \\end{array}\\right.\\)" ], "text/latex": [ "$\\displaystyle \\left\\{\\begin{array}{lcl} x & = & r \\cos\\left({\\phi}\\right) \\sin\\left({\\theta}\\right) \\\\ y & = & r \\sin\\left({\\phi}\\right) \\sin\\left({\\theta}\\right) \\\\ z & = & r \\cos\\left({\\theta}\\right) \\end{array}\\right.$" ], "text/plain": [ "x = r*cos(ph)*sin(th)\n", "y = r*sin(ph)*sin(th)\n", "z = r*cos(th)" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "transit_Y_to_X.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The inverse of the transition map can be specified by means of the method `set_inverse()`:" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Check of the inverse coordinate transformation:\n", " r == r *passed*\n", " th == arctan2(r*sin(th), r*cos(th)) **failed**\n", " ph == arctan2(r*sin(ph)*sin(th), r*cos(ph)*sin(th)) **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": [ "transit_Y_to_X.set_inverse(sqrt(x^2+y^2+z^2), atan2(sqrt(x^2+y^2),z), \n", " atan2(y, x))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A check of the provided inverse is performed by composing it with the original transition map, on the left and on the right respectively. As indicated, the reported failure for `th` and `ph` is actually due to a lack of simplification of expressions involving `arctan2`. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We have then" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left\\{\\begin{array}{lcl} r & = & \\sqrt{x^{2} + y^{2} + z^{2}} \\\\ {\\theta} & = & \\arctan\\left(\\sqrt{x^{2} + y^{2}}, z\\right) \\\\ {\\phi} & = & \\arctan\\left(y, x\\right) \\end{array}\\right.\\)" ], "text/latex": [ "$\\displaystyle \\left\\{\\begin{array}{lcl} r & = & \\sqrt{x^{2} + y^{2} + z^{2}} \\\\ {\\theta} & = & \\arctan\\left(\\sqrt{x^{2} + y^{2}}, z\\right) \\\\ {\\phi} & = & \\arctan\\left(y, x\\right) \\end{array}\\right.$" ], "text/plain": [ "r = sqrt(x^2 + y^2 + z^2)\n", "th = arctan2(sqrt(x^2 + y^2), z)\n", "ph = arctan2(y, x)" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "transit_Y_to_X.inverse().display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

At this stage, the manifold's atlas (the \"user atlas\", not the maximal atlas!) contains three charts:

" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left[\\left(\\mathcal{M},(x, y, z)\\right), \\left(U,(x, y, z)\\right), \\left(U,(r, {\\theta}, {\\phi})\\right)\\right]\\)" ], "text/latex": [ "$\\displaystyle \\left[\\left(\\mathcal{M},(x, y, z)\\right), \\left(U,(x, y, z)\\right), \\left(U,(r, {\\theta}, {\\phi})\\right)\\right]$" ], "text/plain": [ "[Chart (M, (x, y, z)), Chart (U, (x, y, z)), Chart (U, (r, th, ph))]" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "M.atlas()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The first chart defined on the manifold is considered as the manifold's default chart (this can be changed by the method `set_default_chart()`):" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left(\\mathcal{M},(x, y, z)\\right)\\)" ], "text/latex": [ "$\\displaystyle \\left(\\mathcal{M},(x, y, z)\\right)$" ], "text/plain": [ "Chart (M, (x, y, z))" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "M.default_chart()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Each open subset has its own atlas (since an open subset of a manifold is a manifold by itself):

" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left[\\left(U,(x, y, z)\\right), \\left(U,(r, {\\theta}, {\\phi})\\right)\\right]\\)" ], "text/latex": [ "$\\displaystyle \\left[\\left(U,(x, y, z)\\right), \\left(U,(r, {\\theta}, {\\phi})\\right)\\right]$" ], "text/plain": [ "[Chart (U, (x, y, z)), Chart (U, (r, th, ph))]" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "U.atlas()" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left(U,(x, y, z)\\right)\\)" ], "text/latex": [ "$\\displaystyle \\left(U,(x, y, z)\\right)$" ], "text/plain": [ "Chart (U, (x, y, z))" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "U.default_chart()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can draw the chart $Y$ in terms of the chart $X$ via the command `Y.plot(X)`, which shows the lines of constant coordinates from the $Y$ chart in a \"Cartesian frame\" based on the $X$ coordinates:" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "Graphics3d Object" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Y.plot(X)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The method `plot()` allows for many options, to control the number of coordinate lines to be drawn, their style and color, as well as the coordinate ranges (see the [list of all options](http://doc.sagemath.org/html/en/reference/manifolds/sage/manifolds/chart.html#sage.manifolds.chart.RealChart.plot)):" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "Graphics3d Object" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Y.plot(X, ranges={r:(1,2), th:(0,pi/2)}, number_values=4, \n", " color={r:'blue', th:'green', ph:'red'}, aspect_ratio=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Conversly, the chart $X|_{U}$ can be plotted in terms of the chart $Y$ (this is not possible for the whole chart $X$ since its domain is larger than that of chart $Y$):

" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "