{ "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\n", "[SageManifolds](http://sagemanifolds.obspm.fr) project (version 1.3, included in SageMath 8.3).\n", "\n", "Click [here](https://raw.githubusercontent.com/sagemanifolds/SageManifolds/master/Worksheets/v1.3/SM_tutorial.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": [ "The following assumes that you are using version 7.5 (or higher) of SageMath, since lower versions do not include all features of SageManifolds:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'SageMath version 8.3, Release Date: 2018-08-03'" ] }, "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. In SageManifolds, 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 a mere Python variable, which 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": [ "" ], "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 `print` function 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 command 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": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(M)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can 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": [ "" ], "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": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "2\n", "3\n" ] } ], "source": [ "for i in M.irange():\n", " print(i)" ] }, { "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": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "1\n", "2\n" ] } ], "source": [ "M0 = Manifold(3, 'M', r'\\mathcal{M}')\n", "for i in M0.irange():\n", " print(i)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Defining a chart on the manifold

\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": [ "" ], "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": [ "" ], "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": [ "" ], "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": [ "" ], "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": [ "" ], "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": [ "" ], "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": [ "" ], "text/plain": [ "" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(z)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Functions of the chart coordinates

\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": [ "" ], "text/plain": [ "z^3 + y^2 + x" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = X.function(x+y^2+z^3) ; f" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "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": [ "" ], "text/plain": [ "32" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f(1,2,3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

They belong to SageManifolds class ChartFunction:

" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "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": [ "" ], "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": [ "" ], "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": [ "" ], "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": [ "" ], "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": [ "" ], "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": [ "" ], "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": [ "" ], "text/plain": [ "cos(x)^2" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1.expr()" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "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": [ "" ], "text/plain": [ "Chart (U, (x, y, z))" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X_U = X.restrict(U) ; 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": [ "" ], "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') ; Y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The function chart() has now some 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": [ "" ], "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": [ "" ], "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": [ "" ], "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": [ "" ], "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": [ "" ], "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": [], "source": [ "transit_Y_to_X = Y.transition_map(X_U, [r*sin(th)*cos(ph), r*sin(th)*sin(ph), r*cos(th)])" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Change of coordinates from Chart (U, (r, th, ph)) to Chart (U, (x, y, z))" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "transit_Y_to_X" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "x = r*cos(ph)*sin(th)\n", "y = r*sin(ph)*sin(th)\n", "z = r*cos(th)" ] }, "execution_count": 42, "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": 43, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "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.set_inverse(sqrt(x^2+y^2+z^2), atan2(sqrt(x^2+y^2),z), atan2(y, x))\n", "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": [ "" ], "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 (it can be changed by the method set_default_chart()):

" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "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": [ "" ], "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": [ "" ], "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$. \n", "Let us first define a viewer for 3D plots (use `'threejs'` or `'jmol'` for interactive 3D graphics):" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [], "source": [ "viewer3D = 'threejs' # must be 'threejs', 'jmol', 'tachyon' or None (default)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The plot shows lines of constant coordinates from the $Y$ chart in a \"Cartesian frame\" based on the $X$ coordinates:" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "Graphics3d Object" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "graph = Y.plot(X)\n", "show(graph, viewer=viewer3D, online=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The command 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 (cf. 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": 50, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "Graphics3d Object" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "graph = Y.plot(X, ranges={r:(1,2), th:(0,pi/2)}, number_values=4, \n", " color={r:'blue', th:'green', ph:'red'})\n", "show(graph, aspect_ratio=1, viewer=viewer3D, online=True)" ] }, { "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": 51, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "Graphics3d Object" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "graph = X_U.plot(Y)\n", "show(graph, viewer=viewer3D, online=True, axes_labels=['r','theta','phi'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Points on the manifold

\n", "

A point on $\\mathcal{M}$ is defined by its coordinates in a given chart:

" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Point p on the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "Point p on the 3-dimensional differentiable manifold M" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p = M.point((1,2,-1), chart=X, name='p') ; print(p) ; p" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Since $X=(\\mathcal{M}, (x,y,z))$ is the manifold's default chart, its name can be omitted:

" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Point p on the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "Point p on the 3-dimensional differentiable manifold M" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p = M.point((1,2,-1), name='p') ; print(p) ; p" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Of course, $p$ belongs to $\\mathcal{M}$:

" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p in M" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

It is also in $U$:

" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p in U" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Indeed the coordinates of $p$ have $y\\not=0$:

" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "(1, 2, -1)" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.coord(X)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Note in passing that since $X$ is the default chart on $\\mathcal{M}$, its name can be omitted in the arguments of coord():

" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "(1, 2, -1)" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.coord()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The coordinates of $p$ can also be obtained by letting the chart acting of the point (from the very definition of a chart!):

" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "(1, 2, -1)" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X(p)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Let $q$ be a point with $y = 0$ and $x \\geq 0$:

" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [], "source": [ "q = M.point((1,0,2), name='q')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

This time, the point does not belong to $U$:

" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "False" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q in U" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Accordingly, we cannot ask for the coordinates of $q$ in the chart $Y=(U, (r,\\theta,\\phi))$:

" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Error: the point does not belong to the domain of Chart (U, (r, th, ph))\n" ] } ], "source": [ "try:\n", " q.coord(Y)\n", "except ValueError as exc:\n", " print(\"Error: \" + str(exc))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

but we can for point $p$:

" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "(sqrt(3)*sqrt(2), pi - arctan(sqrt(5)), arctan(2))" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.coord(Y)" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "(sqrt(3)*sqrt(2), pi - arctan(sqrt(5)), arctan(2))" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Y(p)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Points can be compared:

" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "False" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q == p" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p1 = U.point((sqrt(3)*sqrt(2), pi-atan(sqrt(5)), atan(2)), chart=Y)\n", "p1 == p" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

In SageMath's terminology, points are elements, whose parents are the manifold on which they have been defined:

" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "3-dimensional differentiable manifold M" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.parent()" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "3-dimensional differentiable manifold M" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q.parent()" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Open subset U of the 3-dimensional differentiable manifold M" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p1.parent()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Scalar fields

\n", "

A scalar field is a differentiable mapping $U \\longrightarrow \\mathbb{R}$, where $U$ is an open subset of $\\mathcal{M}$.

\n", "

The scalar field is defined by its expressions in terms of charts covering its domain (in general more than one chart is necessary to cover all the domain):

" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field f on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "f = U.scalar_field({X_U: x+y^2+z^3}, name='f') ; print(f)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The coordinate expressions of the scalar field are passed as a Python dictionary, with the charts as keys, hence the writing {X_U: x+y^2+z^3}.

\n", "

Since in the present case, there is only one chart in the dictionary, an alternative writing is

" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field f on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "f = U.scalar_field(x+y^2+z^3, chart=X_U, name='f') ; print(f)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Since X_U is the domain's default chart, it can be omitted in the above declaration:

" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field f on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "f = U.scalar_field(x+y^2+z^3, name='f') ; print(f)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a mapping $U\\subset\\mathcal{M}\\longrightarrow\\mathbb{R}$, a scalar field acts on points, not on coordinates:" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "4" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f(p)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The method `display()` provides the expression of the scalar field in terms of a given chart:" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "f: U --> R\n", " (x, y, z) |--> z^3 + y^2 + x" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.display(X_U)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If no argument is provided, the method `display()` shows the coordinate expression of the scalar field in all the charts defined on the domain (except for *subcharts*, i.e. the restrictions of some chart to a subdomain):" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "f: U --> R\n", " (x, y, z) |--> z^3 + y^2 + x\n", " (r, th, ph) |--> r^3*cos(th)^3 + r^2*sin(ph)^2*sin(th)^2 + r*cos(ph)*sin(th)" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Note that the expression of $f$ in terms of the coordinates $(r,\\theta,\\phi)$ has not been provided by the user but has been automatically computed by means of the change-of-coordinate formula declared above in the transition map.

" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "f: U --> R\n", " (r, th, ph) |--> r^3*cos(th)^3 + r^2*sin(ph)^2*sin(th)^2 + r*cos(ph)*sin(th)" ] }, "execution_count": 75, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.display(Y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

In each chart, the scalar field is represented by a function of the chart coordinates (an object of the type CoordFunctionSymb described above), which is accessible via the method coord_function():

" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "z^3 + y^2 + x" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.coord_function(X_U)" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "(x, y, z) |--> z^3 + y^2 + x" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.coord_function(X_U).display()" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "r^3*cos(th)^3 + r^2*sin(ph)^2*sin(th)^2 + r*cos(ph)*sin(th)" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.coord_function(Y)" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "(r, th, ph) |--> r^3*cos(th)^3 + r^2*sin(ph)^2*sin(th)^2 + r*cos(ph)*sin(th)" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.coord_function(Y).display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The \"raw\" symbolic expression is returned by the method expr():

" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "z^3 + y^2 + x" ] }, "execution_count": 80, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.expr(X_U)" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "r^3*cos(th)^3 + r^2*sin(ph)^2*sin(th)^2 + r*cos(ph)*sin(th)" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.expr(Y)" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.expr(Y) is f.coord_function(Y).expr()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

A scalar field can also be defined by some unspecified function of the coordinates:

" ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field h on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "h = U.scalar_field(function('H')(x, y, z), name='h') ; print(h)" ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "h: U --> R\n", " (x, y, z) |--> H(x, y, z)\n", " (r, th, ph) |--> H(r*cos(ph)*sin(th), r*sin(ph)*sin(th), r*cos(th))" ] }, "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ "h.display()" ] }, { "cell_type": "code", "execution_count": 85, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "h: U --> R\n", " (r, th, ph) |--> H(r*cos(ph)*sin(th), r*sin(ph)*sin(th), r*cos(th))" ] }, "execution_count": 85, "metadata": {}, "output_type": "execute_result" } ], "source": [ "h.display(Y)" ] }, { "cell_type": "code", "execution_count": 86, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "H(1, 2, -1)" ] }, "execution_count": 86, "metadata": {}, "output_type": "execute_result" } ], "source": [ "h(p) # remember that p is the point of coordinates (1,2,-1) in the chart X_U" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The parent of $f$ is the set $C^\\infty(U)$ of all smooth scalar fields on $U$, which is a commutative algebra over $\\mathbb{R}$:

" ] }, { "cell_type": "code", "execution_count": 87, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Algebra of differentiable scalar fields on the Open subset U of the 3-dimensional differentiable manifold M" ] }, "execution_count": 87, "metadata": {}, "output_type": "execute_result" } ], "source": [ "CU = f.parent() ; CU" ] }, { "cell_type": "code", "execution_count": 88, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Algebra of differentiable scalar fields on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "print(CU)" ] }, { "cell_type": "code", "execution_count": 89, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Category of commutative algebras over Symbolic Ring" ] }, "execution_count": 89, "metadata": {}, "output_type": "execute_result" } ], "source": [ "CU.category()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
 
\n", "
\n", "

The base ring of the algebra is the field $\\mathbb{R}$, which is represented here by SageMath's Symbolic Ring (SR):

\n", "
\n", "
 
" ] }, { "cell_type": "code", "execution_count": 90, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Symbolic Ring" ] }, "execution_count": 90, "metadata": {}, "output_type": "execute_result" } ], "source": [ "CU.base_ring()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Arithmetic operations on scalar fields are defined through the algebra structure:

" ] }, { "cell_type": "code", "execution_count": 91, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "s = f + 2*h ; print(s)" ] }, { "cell_type": "code", "execution_count": 92, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "U --> R\n", "(x, y, z) |--> z^3 + y^2 + x + 2*H(x, y, z)\n", "(r, th, ph) |--> r^3*cos(th)^3 + r^2*sin(ph)^2*sin(th)^2 + r*cos(ph)*sin(th) + 2*H(r*cos(ph)*sin(th), r*sin(ph)*sin(th), r*cos(th))" ] }, "execution_count": 92, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Tangent spaces

\n", "

The tangent vector space to the manifold at point $p$ is obtained as follows:

" ] }, { "cell_type": "code", "execution_count": 93, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Tangent space at Point p on the 3-dimensional differentiable manifold M" ] }, "execution_count": 93, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Tp = M.tangent_space(p) ; Tp" ] }, { "cell_type": "code", "execution_count": 94, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tangent space at Point p on the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "print(Tp)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

$T_p\\, \\mathcal{M}$ is a 2-dimensional vector space over $\\mathbb{R}$ (represented here by SageMath's Symbolic Ring (SR)) :

" ] }, { "cell_type": "code", "execution_count": 95, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Category of finite dimensional vector spaces over Symbolic Ring\n" ] } ], "source": [ "print(Tp.category())" ] }, { "cell_type": "code", "execution_count": 96, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "3" ] }, "execution_count": 96, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Tp.dim()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

$T_p\\, \\mathcal{M}$ is automatically endowed with vector bases deduced from the vector frames defined around the point:

" ] }, { "cell_type": "code", "execution_count": 97, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[Basis (d/dx,d/dy,d/dz) on the Tangent space at Point p on the 3-dimensional differentiable manifold M,\n", " Basis (d/dr,d/dth,d/dph) on the Tangent space at Point p on the 3-dimensional differentiable manifold M]" ] }, "execution_count": 97, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Tp.bases()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

For the tangent space at the point $q$, on the contrary, there is only one pre-defined basis, since $q$ is not in the domain $U$ of the frame associated with coordinates $(r,\\theta,\\phi)$:

" ] }, { "cell_type": "code", "execution_count": 98, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[Basis (d/dx,d/dy,d/dz) on the Tangent space at Point q on the 3-dimensional differentiable manifold M]" ] }, "execution_count": 98, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Tq = M.tangent_space(q)\n", "Tq.bases()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

A random element:

" ] }, { "cell_type": "code", "execution_count": 99, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tangent vector at Point p on the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "v = Tp.an_element() ; print(v)" ] }, { "cell_type": "code", "execution_count": 100, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "d/dx + 2 d/dy + 3 d/dz" ] }, "execution_count": 100, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.display()" ] }, { "cell_type": "code", "execution_count": 101, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tangent vector at Point q on the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "u = Tq.an_element() ; print(u)" ] }, { "cell_type": "code", "execution_count": 102, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "d/dx + 2 d/dy + 3 d/dz" ] }, "execution_count": 102, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Note that, despite what the above simplified writing may suggest (the mention of the point $p$ or $q$ is omitted in the basis vectors), $u$ and $v$ are different vectors, for they belong to different vector spaces:

" ] }, { "cell_type": "code", "execution_count": 103, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Tangent space at Point p on the 3-dimensional differentiable manifold M" ] }, "execution_count": 103, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.parent()" ] }, { "cell_type": "code", "execution_count": 104, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Tangent space at Point q on the 3-dimensional differentiable manifold M" ] }, "execution_count": 104, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u.parent()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

In particular, it is not possible to add $u$ and $v$:

" ] }, { "cell_type": "code", "execution_count": 105, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Error: unsupported operand parent(s) for +: 'Tangent space at Point q on the 3-dimensional differentiable manifold M' and 'Tangent space at Point p on the 3-dimensional differentiable manifold M'\n" ] } ], "source": [ "try:\n", " s = u + v\n", "except TypeError as exc:\n", " print(\"Error: \" + str(exc))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Vector Fields

\n", "

Each chart defines a vector frame on the chart domain: the so-called coordinate basis:

" ] }, { "cell_type": "code", "execution_count": 106, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Coordinate frame (M, (d/dx,d/dy,d/dz))" ] }, "execution_count": 106, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X.frame()" ] }, { "cell_type": "code", "execution_count": 107, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "3-dimensional differentiable manifold M" ] }, "execution_count": 107, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X.frame().domain() # this frame is defined on the whole manifold" ] }, { "cell_type": "code", "execution_count": 108, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Coordinate frame (U, (d/dr,d/dth,d/dph))" ] }, "execution_count": 108, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Y.frame()" ] }, { "cell_type": "code", "execution_count": 109, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Open subset U of the 3-dimensional differentiable manifold M" ] }, "execution_count": 109, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Y.frame().domain() # this frame is defined only on U" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The list of frames defined on a given open subset is returned by the method frames():

" ] }, { "cell_type": "code", "execution_count": 110, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[Coordinate frame (M, (d/dx,d/dy,d/dz)),\n", " Coordinate frame (U, (d/dx,d/dy,d/dz)),\n", " Coordinate frame (U, (d/dr,d/dth,d/dph))]" ] }, "execution_count": 110, "metadata": {}, "output_type": "execute_result" } ], "source": [ "M.frames()" ] }, { "cell_type": "code", "execution_count": 111, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[Coordinate frame (U, (d/dx,d/dy,d/dz)),\n", " Coordinate frame (U, (d/dr,d/dth,d/dph))]" ] }, "execution_count": 111, "metadata": {}, "output_type": "execute_result" } ], "source": [ "U.frames()" ] }, { "cell_type": "code", "execution_count": 112, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Coordinate frame (M, (d/dx,d/dy,d/dz))" ] }, "execution_count": 112, "metadata": {}, "output_type": "execute_result" } ], "source": [ "M.default_frame()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Unless otherwise specified (via the command set_default_frame()), the default frame is that associated with the default chart:

" ] }, { "cell_type": "code", "execution_count": 113, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 113, "metadata": {}, "output_type": "execute_result" } ], "source": [ "M.default_frame() is M.default_chart().frame()" ] }, { "cell_type": "code", "execution_count": 114, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 114, "metadata": {}, "output_type": "execute_result" } ], "source": [ "U.default_frame() is U.default_chart().frame()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Individual elements of a frame can be accessed by means of their indices:

" ] }, { "cell_type": "code", "execution_count": 115, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Vector field d/dy on the Open subset U of the 3-dimensional differentiable manifold M" ] }, "execution_count": 115, "metadata": {}, "output_type": "execute_result" } ], "source": [ "e = U.default_frame() ; e2 = e[2] ; e2" ] }, { "cell_type": "code", "execution_count": 116, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Vector field d/dy on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "print(e2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

We may define a new vector field as follows:

" ] }, { "cell_type": "code", "execution_count": 117, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Vector field on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "v = e[2] + 2*x*e[3] ; print(v)" ] }, { "cell_type": "code", "execution_count": 118, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "d/dy + 2*x d/dz" ] }, "execution_count": 118, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

A vector field can be defined by its components with respect to a given vector frame. When the latter is not specified, the open set's default frame is of course assumed:

" ] }, { "cell_type": "code", "execution_count": 119, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v = (y + 1) d/dx - x d/dy + x*y*z d/dz" ] }, "execution_count": 119, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v = U.vector_field(name='v') # vector field defined on the open set U\n", "v[1] = 1+y\n", "v[2] = -x\n", "v[3] = x*y*z\n", "v.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Vector fields on $U$ are Sage element objects, whose parent is the set $\\mathfrak{X}(U)$ of vector fields defined on $U$:

" ] }, { "cell_type": "code", "execution_count": 120, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Free module X(U) of vector fields on the Open subset U of the 3-dimensional differentiable manifold M" ] }, "execution_count": 120, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.parent()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The set $\\mathfrak{X}(U)$ is a module over the commutative algebra $C^\\infty(U)$ of scalar fields on $U$:

" ] }, { "cell_type": "code", "execution_count": 121, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Free module X(U) of vector fields on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "print(v.parent())" ] }, { "cell_type": "code", "execution_count": 122, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Category of finite dimensional modules over Algebra of differentiable scalar fields on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "print(v.parent().category())" ] }, { "cell_type": "code", "execution_count": 123, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Algebra of differentiable scalar fields on the Open subset U of the 3-dimensional differentiable manifold M" ] }, "execution_count": 123, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.parent().base_ring()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

A vector field acts on scalar fields:

" ] }, { "cell_type": "code", "execution_count": 124, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "f: U --> R\n", " (x, y, z) |--> z^3 + y^2 + x\n", " (r, th, ph) |--> r^3*cos(th)^3 + r^2*sin(ph)^2*sin(th)^2 + r*cos(ph)*sin(th)" ] }, "execution_count": 124, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.display()" ] }, { "cell_type": "code", "execution_count": 125, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field v(f) on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "s = v(f) ; print(s)" ] }, { "cell_type": "code", "execution_count": 126, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v(f): U --> R\n", " (x, y, z) |--> 3*x*y*z^3 - (2*x - 1)*y + 1\n", " (r, th, ph) |--> -3*r^5*cos(ph)*cos(th)^5*sin(ph) + 3*r^5*cos(ph)*cos(th)^3*sin(ph) - 2*r^2*cos(ph)*sin(ph)*sin(th)^2 + r*sin(ph)*sin(th) + 1" ] }, "execution_count": 126, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s.display()" ] }, { "cell_type": "code", "execution_count": 127, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "d/dz = d/dz" ] }, "execution_count": 127, "metadata": {}, "output_type": "execute_result" } ], "source": [ "e[3].display()" ] }, { "cell_type": "code", "execution_count": 128, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "d/dz(f): U --> R\n", " (x, y, z) |--> 3*z^2\n", " (r, th, ph) |--> 3*r^2*cos(th)^2" ] }, "execution_count": 128, "metadata": {}, "output_type": "execute_result" } ], "source": [ "e[3](f).display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Unset components are assumed to be zero:

" ] }, { "cell_type": "code", "execution_count": 129, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "w = 3 d/dy" ] }, "execution_count": 129, "metadata": {}, "output_type": "execute_result" } ], "source": [ "w = U.vector_field(name='w')\n", "w[2] = 3\n", "w.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

A vector field on $U$ can be expanded in the vector frame associated with the chart $(r,\\theta,\\phi)$:

" ] }, { "cell_type": "code", "execution_count": 130, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v = (x*y*z^2 + x)/sqrt(x^2 + y^2 + z^2) d/dr - (x^3*y + x*y^3 - x)*sqrt(x^2 + y^2)*z/(x^4 + 2*x^2*y^2 + y^4 + (x^2 + y^2)*z^2) d/dth - (x^2 + y^2 + y)/(x^2 + y^2) d/dph" ] }, "execution_count": 130, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.display(Y.frame())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

By default, the components are expressed in terms of the default coordinates $(x,y,z)$. To express them in terms of the coordinates $(r,\\theta,\\phi)$, one should add the corresponding chart as the second argument of the method display():

" ] }, { "cell_type": "code", "execution_count": 131, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v = (r^3*cos(ph)*cos(th)^2*sin(ph)*sin(th)^2 + cos(ph)*sin(th)) d/dr - (r^3*cos(ph)*cos(th)*sin(ph)*sin(th)^3 - cos(ph)*cos(th))/r d/dth - (r*sin(th) + sin(ph))/(r*sin(th)) d/dph" ] }, "execution_count": 131, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.display(Y.frame(), Y)" ] }, { "cell_type": "code", "execution_count": 132, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "d/dx = cos(ph)*sin(th) d/dr + cos(ph)*cos(th)/r d/dth - sin(ph)/(r*sin(th)) d/dph" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "d/dy = sin(ph)*sin(th) d/dr + cos(th)*sin(ph)/r d/dth + cos(ph)/(r*sin(th)) d/dph" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "d/dz = cos(th) d/dr - sin(th)/r d/dth" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "for i in M.irange(): \n", " show(e[i].display(Y.frame(), Y))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The components of a tensor field w.r.t. the default frame can also be obtained as a list, via the command [:]:

" ] }, { "cell_type": "code", "execution_count": 133, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[y + 1, -x, x*y*z]" ] }, "execution_count": 133, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v[:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

An alternative is to use the method display_comp():

" ] }, { "cell_type": "code", "execution_count": 134, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v^x = y + 1 \n", "v^y = -x \n", "v^z = x*y*z " ] }, "execution_count": 134, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.display_comp()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

To obtain the components w.r.t. to another frame, one may go through the method comp() and specify the frame:

" ] }, { "cell_type": "code", "execution_count": 135, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[(x*y*z^2 + x)/sqrt(x^2 + y^2 + z^2),\n", " -(x^3*y + x*y^3 - x)*sqrt(x^2 + y^2)*z/(x^4 + 2*x^2*y^2 + y^4 + (x^2 + y^2)*z^2),\n", " -(x^2 + y^2 + y)/(x^2 + y^2)]" ] }, "execution_count": 135, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.comp(Y.frame())[:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

However a shortcut is to provide the frame as the first argument of the square brackets:

" ] }, { "cell_type": "code", "execution_count": 136, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[(x*y*z^2 + x)/sqrt(x^2 + y^2 + z^2),\n", " -(x^3*y + x*y^3 - x)*sqrt(x^2 + y^2)*z/(x^4 + 2*x^2*y^2 + y^4 + (x^2 + y^2)*z^2),\n", " -(x^2 + y^2 + y)/(x^2 + y^2)]" ] }, "execution_count": 136, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v[Y.frame(), :]" ] }, { "cell_type": "code", "execution_count": 137, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v^r = (x*y*z^2 + x)/sqrt(x^2 + y^2 + z^2) \n", "v^th = -(x^3*y + x*y^3 - x)*sqrt(x^2 + y^2)*z/(x^4 + 2*x^2*y^2 + y^4 + (x^2 + y^2)*z^2) \n", "v^ph = -(x^2 + y^2 + y)/(x^2 + y^2) " ] }, "execution_count": 137, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.display_comp(Y.frame())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Components are shown expressed in terms of the default's coordinates; to get them in terms of the coordinates $(r,\\theta,\\phi)$ instead, add the chart name as the last argument in the square brackets:

" ] }, { "cell_type": "code", "execution_count": 138, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[r^3*cos(ph)*cos(th)^2*sin(ph)*sin(th)^2 + cos(ph)*sin(th),\n", " -(r^3*cos(ph)*cos(th)*sin(ph)*sin(th)^3 - cos(ph)*cos(th))/r,\n", " -(r*sin(th) + sin(ph))/(r*sin(th))]" ] }, "execution_count": 138, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v[Y.frame(), :, Y]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

or specify the chart in display_comp():

" ] }, { "cell_type": "code", "execution_count": 139, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v^r = r^3*cos(ph)*cos(th)^2*sin(ph)*sin(th)^2 + cos(ph)*sin(th) \n", "v^th = -(r^3*cos(ph)*cos(th)*sin(ph)*sin(th)^3 - cos(ph)*cos(th))/r \n", "v^ph = -(r*sin(th) + sin(ph))/(r*sin(th)) " ] }, "execution_count": 139, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.display_comp(Y.frame(), chart=Y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To get some vector component as a scalar field instead of a coordinate expression, use double square brackets:" ] }, { "cell_type": "code", "execution_count": 140, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "print(v[[1]])" ] }, { "cell_type": "code", "execution_count": 141, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "U --> R\n", "(x, y, z) |--> y + 1\n", "(r, th, ph) |--> r*sin(ph)*sin(th) + 1" ] }, "execution_count": 141, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v[[1]].display()" ] }, { "cell_type": "code", "execution_count": 142, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "y + 1" ] }, "execution_count": 142, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v[[1]].expr(X_U)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

A vector field can be defined with components being unspecified functions of the coordinates:

" ] }, { "cell_type": "code", "execution_count": 143, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "u = u_x(x, y, z) d/dx + u_y(x, y, z) d/dy + u_z(x, y, z) d/dz" ] }, "execution_count": 143, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u = U.vector_field(name='u')\n", "u[:] = [function('u_x')(x,y,z), function('u_y')(x,y,z), function('u_z')(x,y,z)]\n", "u.display()" ] }, { "cell_type": "code", "execution_count": 144, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "s = (y + u_x(x, y, z) + 1) d/dx + (-x + u_y(x, y, z)) d/dy + (x*y*z + u_z(x, y, z)) d/dz" ] }, "execution_count": 144, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s = v + u ; s.set_name('s') ; s.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Values of vector fields at a given point

\n", "

The value of a vector field at some point of the manifold is obtained via the method at():

" ] }, { "cell_type": "code", "execution_count": 145, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tangent vector v at Point p on the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "vp = v.at(p) ; print(vp)" ] }, { "cell_type": "code", "execution_count": 146, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v = 3 d/dx - d/dy - 2 d/dz" ] }, "execution_count": 146, "metadata": {}, "output_type": "execute_result" } ], "source": [ "vp.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Indeed, recall that, w.r.t. chart X_U=$(x,y,z)$,  the coordinates of the point $p$ and the components of the vector field $v$ are

" ] }, { "cell_type": "code", "execution_count": 147, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "(1, 2, -1)" ] }, "execution_count": 147, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.coord(X_U)" ] }, { "cell_type": "code", "execution_count": 148, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v = (y + 1) d/dx - x d/dy + x*y*z d/dz" ] }, "execution_count": 148, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.display(X_U.frame(), X_U)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Note that to simplify the writing, the symbol used to denote the value of the vector field at point $p$ is the same as that of the vector field itself (namely $v$); this can be changed by the method set_name():

" ] }, { "cell_type": "code", "execution_count": 149, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "v = 3 d/dx - d/dy - 2 d/dz" ] }, "execution_count": 149, "metadata": {}, "output_type": "execute_result" } ], "source": [ "vp.set_name(latex_name='v|_p')\n", "vp.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Of course, $v|_p$ belongs to the tangent space at $p$:

" ] }, { "cell_type": "code", "execution_count": 150, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Tangent space at Point p on the 3-dimensional differentiable manifold M" ] }, "execution_count": 150, "metadata": {}, "output_type": "execute_result" } ], "source": [ "vp.parent()" ] }, { "cell_type": "code", "execution_count": 151, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 151, "metadata": {}, "output_type": "execute_result" } ], "source": [ "vp in M.tangent_space(p)" ] }, { "cell_type": "code", "execution_count": 152, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tangent vector u at Point p on the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "up = u.at(p) ; print(up)" ] }, { "cell_type": "code", "execution_count": 153, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "u = u_x(1, 2, -1) d/dx + u_y(1, 2, -1) d/dy + u_z(1, 2, -1) d/dz" ] }, "execution_count": 153, "metadata": {}, "output_type": "execute_result" } ], "source": [ "up.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

1-forms

\n", "

A 1-form on $\\mathcal{M}$ is a field of linear forms. For instance, it can be the differential of a scalar field:

" ] }, { "cell_type": "code", "execution_count": 154, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1-form df on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "df = f.differential() ; print(df)" ] }, { "cell_type": "code", "execution_count": 155, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "df = dx + 2*y dy + 3*z^2 dz" ] }, "execution_count": 155, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

In the above writing, the 1-form is expanded over the basis $(\\mathrm{d}x, \\mathrm{d}y, \\mathrm{d}z)$ associated with the chart $(x,y,z)$. This basis can be accessed via the method coframe():

" ] }, { "cell_type": "code", "execution_count": 156, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Coordinate coframe (M, (dx,dy,dz))" ] }, "execution_count": 156, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dX = X.coframe() ; dX" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The list of all coframes defined on a given manifold open subset is returned by the method coframes():

" ] }, { "cell_type": "code", "execution_count": 157, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[Coordinate coframe (M, (dx,dy,dz)),\n", " Coordinate coframe (U, (dx,dy,dz)),\n", " Coordinate coframe (U, (dr,dth,dph))]" ] }, "execution_count": 157, "metadata": {}, "output_type": "execute_result" } ], "source": [ "M.coframes()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

As for a vector field, the value of the differential form at some point on the manifold is obtained by the method at():

" ] }, { "cell_type": "code", "execution_count": 158, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Linear form df on the Tangent space at Point p on the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "dfp = df.at(p) ; print(dfp)" ] }, { "cell_type": "code", "execution_count": 159, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "df = dx + 4 dy + 3 dz" ] }, "execution_count": 159, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dfp.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Recall that

" ] }, { "cell_type": "code", "execution_count": 160, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "(1, 2, -1)" ] }, "execution_count": 160, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.coord()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The linear form $\\mathrm{d}f|_p$ belongs to the dual of the tangent vector space at $p$:

" ] }, { "cell_type": "code", "execution_count": 161, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Dual of the Tangent space at Point p on the 3-dimensional differentiable manifold M" ] }, "execution_count": 161, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dfp.parent()" ] }, { "cell_type": "code", "execution_count": 162, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 162, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dfp.parent() is M.tangent_space(p).dual()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

As such, it is acting on vectors at $p$, yielding a real number:

" ] }, { "cell_type": "code", "execution_count": 163, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tangent vector v at Point p on the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "v = 3 d/dx - d/dy - 2 d/dz" ] }, "execution_count": 163, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(vp) ; vp.display()" ] }, { "cell_type": "code", "execution_count": 164, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "-7" ] }, "execution_count": 164, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dfp(vp)" ] }, { "cell_type": "code", "execution_count": 165, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tangent vector u at Point p on the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "u = u_x(1, 2, -1) d/dx + u_y(1, 2, -1) d/dy + u_z(1, 2, -1) d/dz" ] }, "execution_count": 165, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(up) ; up.display()" ] }, { "cell_type": "code", "execution_count": 166, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "u_x(1, 2, -1) + 4*u_y(1, 2, -1) + 3*u_z(1, 2, -1)" ] }, "execution_count": 166, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dfp(up)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The differential 1-form of the unspecified scalar field $h$:

" ] }, { "cell_type": "code", "execution_count": 167, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "dh = d(H)/dx dx + d(H)/dy dy + d(H)/dz dz" ] }, "execution_count": 167, "metadata": {}, "output_type": "execute_result" } ], "source": [ "h.display() ; dh = h.differential() ; dh.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

A 1-form can also be defined from scratch:

" ] }, { "cell_type": "code", "execution_count": 168, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1-form omega on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "om = U.one_form('omega', r'\\omega') ; print(om)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

It can be specified by providing its components in a given coframe:

" ] }, { "cell_type": "code", "execution_count": 169, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "omega = (x^2 + y^2) dx + z dy + (x - z) dz" ] }, "execution_count": 169, "metadata": {}, "output_type": "execute_result" } ], "source": [ "om[:] = [x^2+y^2, z, x-z] # components in the default coframe (dx,dy,dz)\n", "om.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Of course, one may set the components in a frame different from the default one:

" ] }, { "cell_type": "code", "execution_count": 170, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "omega = r*cos(ph)*sin(th) dr + r*sin(ph)*sin(th) dph" ] }, "execution_count": 170, "metadata": {}, "output_type": "execute_result" } ], "source": [ "om[Y.frame(), :, Y] = [r*sin(th)*cos(ph), 0, r*sin(th)*sin(ph)]\n", "om.display(Y.frame(), Y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The components in the coframe $(\\mathrm{d}x,\\mathrm{d}y,\\mathrm{d}z)$ are updated automatically:

" ] }, { "cell_type": "code", "execution_count": 171, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "omega = (x^4 + x^2*y^2 - sqrt(x^2 + y^2 + z^2)*y^2)/(sqrt(x^2 + y^2 + z^2)*(x^2 + y^2)) dx + (x^3*y + x*y^3 + sqrt(x^2 + y^2 + z^2)*x*y)/(sqrt(x^2 + y^2 + z^2)*(x^2 + y^2)) dy + x*z/sqrt(x^2 + y^2 + z^2) dz" ] }, "execution_count": 171, "metadata": {}, "output_type": "execute_result" } ], "source": [ "om.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Let us revert to the values set previously:

" ] }, { "cell_type": "code", "execution_count": 172, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "omega = (x^2 + y^2) dx + z dy + (x - z) dz" ] }, "execution_count": 172, "metadata": {}, "output_type": "execute_result" } ], "source": [ "om[:] = [x^2+y^2, z, x-z]\n", "om.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

This time, the components in the coframe $(\\mathrm{d}r, \\mathrm{d}\\theta,\\mathrm{d}\\phi)$ are those that are updated:

" ] }, { "cell_type": "code", "execution_count": 173, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "omega = (r^2*cos(ph)*sin(th)^3 + r*(cos(ph) + sin(ph))*cos(th)*sin(th) - r*cos(th)^2) dr + (r^2*cos(th)^2*sin(ph) + r^2*cos(th)*sin(th) + (r^3*cos(ph)*cos(th) - r^2*cos(ph))*sin(th)^2) dth + (-r^3*sin(ph)*sin(th)^3 + r^2*cos(ph)*cos(th)*sin(th)) dph" ] }, "execution_count": 173, "metadata": {}, "output_type": "execute_result" } ], "source": [ "om.display(Y.frame(), Y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

A 1-form acts on vector fields, resulting in a scalar field:

" ] }, { "cell_type": "code", "execution_count": 174, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field omega(v) on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "omega(v): U --> R\n", " (x, y, z) |--> -x*y*z^2 + x^2*y + y^3 + x^2 + y^2 + (x^2*y - x)*z\n", " (r, th, ph) |--> -r^2*cos(ph)*cos(th)*sin(th) + (r^4*cos(ph)^2*cos(th)*sin(ph) + r^3*sin(ph))*sin(th)^3 - (r^4*cos(ph)*cos(th)^2*sin(ph) - r^2)*sin(th)^2" ] }, "execution_count": 174, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.display() ; om.display() ; print(om(v)) ; om(v).display()" ] }, { "cell_type": "code", "execution_count": 175, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field df(v) on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "df(v): U --> R\n", " (x, y, z) |--> 3*x*y*z^3 - (2*x - 1)*y + 1\n", " (r, th, ph) |--> r*sin(ph)*sin(th) + (3*r^5*cos(ph)*cos(th)^3*sin(ph) - 2*r^2*cos(ph)*sin(ph))*sin(th)^2 + 1" ] }, "execution_count": 175, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.display() ; print(df(v)) ; df(v).display()" ] }, { "cell_type": "code", "execution_count": 176, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "omega(u): U --> R\n", " (x, y, z) |--> x^2*u_x(x, y, z) + y^2*u_x(x, y, z) + z*(u_y(x, y, z) - u_z(x, y, z)) + x*u_z(x, y, z)\n", " (r, th, ph) |--> r^2*sin(th)^2*u_x(r*cos(ph)*sin(th), r*sin(ph)*sin(th), r*cos(th)) + r*cos(th)*u_y(r*cos(ph)*sin(th), r*sin(ph)*sin(th), r*cos(th)) + (r*cos(ph)*sin(th) - r*cos(th))*u_z(r*cos(ph)*sin(th), r*sin(ph)*sin(th), r*cos(th))" ] }, "execution_count": 176, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u.display() ; om(u).display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

In the case of a differential 1-form, the following identity holds:

" ] }, { "cell_type": "code", "execution_count": 177, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 177, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df(v) == v(f)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1-forms are Sage *element* objects, whose *parent* is the $C^\\infty(U)$-module $\\Omega^{1}(U)$ of all 1-forms defined on $U$:" ] }, { "cell_type": "code", "execution_count": 178, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Free module Omega^1(U) of 1-forms on the Open subset U of the 3-dimensional differentiable manifold M" ] }, "execution_count": 178, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.parent()" ] }, { "cell_type": "code", "execution_count": 179, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Free module Omega^1(U) of 1-forms on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "print(df.parent())" ] }, { "cell_type": "code", "execution_count": 180, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Free module Omega^1(U) of 1-forms on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "print(om.parent())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$\\Omega^{1}(U)$ is actually the dual of the free module $\\mathfrak{X}(U)$:" ] }, { "cell_type": "code", "execution_count": 181, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 181, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.parent() is v.parent().dual()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Differential forms and exterior calculus

\n", "

The exterior product of two 1-forms is taken via the method wedge() and results in a 2-form:

" ] }, { "cell_type": "code", "execution_count": 182, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2-form omega/\\df on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "omega/\\df = (2*x^2*y + 2*y^3 - z) dx/\\dy + (3*(x^2 + y^2)*z^2 - x + z) dx/\\dz + (3*z^3 - 2*x*y + 2*y*z) dy/\\dz" ] }, "execution_count": 182, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = om.wedge(df) ; print(a) ; a.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

A matrix view of the components:

" ] }, { "cell_type": "code", "execution_count": 183, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[ 0 2*x^2*y + 2*y^3 - z 3*(x^2 + y^2)*z^2 - x + z]\n", "[ -2*x^2*y - 2*y^3 + z 0 3*z^3 - 2*x*y + 2*y*z]\n", "[-3*(x^2 + y^2)*z^2 + x - z -3*z^3 + 2*x*y - 2*y*z 0]" ] }, "execution_count": 183, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Displaying only the non-vanishing components, skipping the redundant ones (i.e. those that can be deduced by antisymmetry):

" ] }, { "cell_type": "code", "execution_count": 184, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "omega/\\df_xy = 2*x^2*y + 2*y^3 - z \n", "omega/\\df_xz = 3*(x^2 + y^2)*z^2 - x + z \n", "omega/\\df_yz = 3*z^3 - 2*x*y + 2*y*z " ] }, "execution_count": 184, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.display_comp(only_nonredundant=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The 2-form $\\omega\\wedge\\mathrm{d}f$ can be expanded on the $(\\mathrm{d}r,\\mathrm{d}\\theta,\\mathrm{d}\\phi)$ coframe:

" ] }, { "cell_type": "code", "execution_count": 185, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "omega/\\df = (3*r^5*cos(ph)*sin(th)^4 - (3*r^5*cos(ph) - 3*r^4*cos(th)*sin(ph) - 2*r^3*cos(ph)*sin(ph)^2)*sin(th)^2 - (3*r^4*sin(ph) + r^2*cos(ph))*cos(th) - (2*r^3*cos(th)*sin(ph)^2 + (sin(ph)^2 - 1)*r^2)*sin(th)) dr/\\dth + (2*r^4*sin(ph)*sin(th)^5 + (3*r^5*cos(th)^3*sin(ph) + 2*r^3*cos(ph)^2*cos(th)*sin(ph))*sin(th)^3 - (2*r^3*cos(ph)*cos(th)^2*sin(ph) + (cos(ph)*sin(ph) + 1)*r^2*cos(th))*sin(th)^2 - (3*r^4*cos(ph)*cos(th)^4 - r^2*cos(th)^2*sin(ph))*sin(th)) dr/\\dph + (-r^3*cos(th)^2*sin(th) - (3*r^6*cos(th)^2*sin(ph) + 2*r^4*cos(ph)^2*sin(ph) - 2*r^5*cos(th)*sin(ph))*sin(th)^4 + (2*r^4*cos(ph)*cos(th)*sin(ph) + r^3*cos(ph)*sin(ph))*sin(th)^3 + (3*r^5*cos(ph)*cos(th)^3 - r^3*cos(th)*sin(ph))*sin(th)^2) dth/\\dph" ] }, "execution_count": 185, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.display(Y.frame(), Y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

As a 2-form, $A:=\\omega\\wedge\\mathrm{d}f$ can be applied to a pair of vectors and is antisymmetric:

" ] }, { "cell_type": "code", "execution_count": 186, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field A(u,v) on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "A(u,v): U --> R\n", " (x, y, z) |--> 3*x*y*z^4*u_y(x, y, z) - 2*x^2*y^2*u_y(x, y, z) - 2*y^4*u_y(x, y, z) - 2*(x*u_x(x, y, z) + u_y(x, y, z))*y^3 + 3*(x^3*y*u_x(x, y, z) + x*y^3*u_x(x, y, z) + x*u_z(x, y, z))*z^3 - (3*y^3*u_z(x, y, z) - (2*x*u_y(x, y, z) - 3*u_z(x, y, z))*y^2 + 3*x^2*u_z(x, y, z) + (3*x^2*u_z(x, y, z) - x*u_x(x, y, z))*y)*z^2 - (2*x^3*u_x(x, y, z) + 2*x^2*u_y(x, y, z) + (2*x^2 - x)*u_z(x, y, z))*y - (2*x^2*y^2*u_y(x, y, z) + (x^2*u_x(x, y, z) - (2*x - 1)*u_z(x, y, z) - u_y(x, y, z))*y - x*u_x(x, y, z) - u_y(x, y, z) + u_z(x, y, z))*z + x*u_z(x, y, z)\n", " (r, th, ph) |--> (r^4*cos(ph)*cos(th)^2*sin(ph)*sin(th)^2 + (sin(ph)^3 - sin(ph))*r^4*cos(th)*sin(th)^3 + r^2*cos(ph)*cos(th)*sin(th) + (3*r^7*cos(ph)*cos(th)^3*sin(ph) - 2*r^4*cos(ph)*sin(ph))*sin(th)^4)*u_x(r*cos(ph)*sin(th), r*sin(ph)*sin(th), r*cos(th)) + (3*r^6*cos(ph)*cos(th)^4*sin(ph)*sin(th)^2 + r^2*cos(th)*sin(ph)*sin(th) + 2*((sin(ph)^4 - sin(ph)^2)*r^5*cos(th) - r^4*sin(ph)^2)*sin(th)^4 + 2*(r^5*cos(ph)*cos(th)^2*sin(ph)^2 - r^3*sin(ph))*sin(th)^3 + r*cos(th))*u_y(r*cos(ph)*sin(th), r*sin(ph)*sin(th), r*cos(th)) - ((3*r^5*cos(th)^2*sin(ph) - 2*(sin(ph)^3 - sin(ph))*r^3)*sin(th)^3 + (3*r^4*cos(th)^2 - 2*r^3*cos(ph)*cos(th)*sin(ph) - r^2*cos(ph)*sin(ph))*sin(th)^2 + r*cos(th) - (3*r^4*cos(ph)*cos(th)^3 - r^2*cos(th)*sin(ph) + r*cos(ph))*sin(th))*u_z(r*cos(ph)*sin(th), r*sin(ph)*sin(th), r*cos(th))" ] }, "execution_count": 186, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.set_name('A')\n", "print(a(u,v)) ; a(u,v).display()" ] }, { "cell_type": "code", "execution_count": 187, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 187, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a(u,v) == - a(v,u)" ] }, { "cell_type": "code", "execution_count": 188, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "no symmetry; antisymmetry: (0, 1)\n" ] } ], "source": [ "a.symmetries()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The exterior derivative  of a differential form:

" ] }, { "cell_type": "code", "execution_count": 189, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2-form domega on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "domega = -2*y dx/\\dy + dx/\\dz - dy/\\dz" ] }, "execution_count": 189, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dom = om.exterior_derivative() ; print(dom) ; dom.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Instead of invoking the method exterior_derivative(), one can use the function xder, after having imported it from sage.manifolds.utilities:

" ] }, { "cell_type": "code", "execution_count": 190, "metadata": {}, "outputs": [], "source": [ "from sage.manifolds.utilities import xder\n", "dom = xder(om)" ] }, { "cell_type": "code", "execution_count": 191, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3-form dA on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "dA = (-6*y*z^2 - 2*y - 1) dx/\\dy/\\dz" ] }, "execution_count": 191, "metadata": {}, "output_type": "execute_result" } ], "source": [ "da = xder(a) ; print(da) ; da.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The exterior derivative is nilpotent:

" ] }, { "cell_type": "code", "execution_count": 192, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "ddf = 0" ] }, "execution_count": 192, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ddf = xder(df) ; ddf.display()" ] }, { "cell_type": "code", "execution_count": 193, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "ddomega = 0" ] }, "execution_count": 193, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ddom = xder(dom) ; ddom.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Lie derivative

\n", "

The Lie derivative of any tensor field with respect to a vector field is computed by the method lie_derivative(), with the vector field as the argument:

" ] }, { "cell_type": "code", "execution_count": 194, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1-form on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "(-y*z^2 + (x*y - 1)*z + 2*x) dx + (-x*z^2 + x^2 + y^2 + (x^2 + x*y)*z) dy + (-2*x*y*z + (x^2 + 1)*y + 1) dz" ] }, "execution_count": 194, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lv_om = om.lie_derivative(v) ; print(lv_om) ; lv_om.display()" ] }, { "cell_type": "code", "execution_count": 195, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1-form on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "(u_x(x, y, z)*d^2(H)/dx^2 + u_y(x, y, z)*d^2(H)/dxdy + u_z(x, y, z)*d^2(H)/dxdz + d(H)/dx*d(u_x)/dx + d(H)/dy*d(u_y)/dx + d(H)/dz*d(u_z)/dx) dx + (u_x(x, y, z)*d^2(H)/dxdy + u_y(x, y, z)*d^2(H)/dy^2 + u_z(x, y, z)*d^2(H)/dydz + d(H)/dx*d(u_x)/dy + d(H)/dy*d(u_y)/dy + d(H)/dz*d(u_z)/dy) dy + (u_x(x, y, z)*d^2(H)/dxdz + u_y(x, y, z)*d^2(H)/dydz + u_z(x, y, z)*d^2(H)/dz^2 + d(H)/dx*d(u_x)/dz + d(H)/dy*d(u_y)/dz + d(H)/dz*d(u_z)/dz) dz" ] }, "execution_count": 195, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lu_dh = dh.lie_derivative(u) ; print(lu_dh) ; lu_dh.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Let us check Cartan identity on the 1-form $\\omega$:

\n", "

$\\mathcal{L}_v \\omega = v\\cdot \\mathrm{d}\\omega + \\mathrm{d}\\langle \\omega, v\\rangle$

\n", "

and on the 2-form $A$:

\n", "

$\\mathcal{L}_v A = v\\cdot \\mathrm{d}A + \\mathrm{d}(v\\cdot A)$

" ] }, { "cell_type": "code", "execution_count": 196, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 196, "metadata": {}, "output_type": "execute_result" } ], "source": [ "om.lie_derivative(v) == v.contract(xder(om)) + xder(om(v))" ] }, { "cell_type": "code", "execution_count": 197, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 197, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.lie_derivative(v) == v.contract(xder(a)) + xder(v.contract(a))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The Lie derivative of a vector field along another one is the commutator of the two vectors fields:

" ] }, { "cell_type": "code", "execution_count": 198, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 198, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.lie_derivative(u)(f) == u(v(f)) - v(u(f))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Tensor fields of arbitrary rank

\n", "

Up to now, we have encountered tensor fields

\n", "
    \n", "
  • of type (0,0) (i.e. scalar fields),
  • \n", "
  • of type (1,0) (i.e. vector fields),
  • \n", "
  • of type (0,1) (i.e. 1-forms),
  • \n", "
  • of type (0,2) and antisymmetric (i.e. 2-forms).
  • \n", "
\n", "

More generally, tensor fields of any type $(p,q)$ can be introduced in SageManifolds. For instance a tensor field of type (1,2) on the open subset $U$ is declared as follows:

" ] }, { "cell_type": "code", "execution_count": 199, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tensor field T of type (1,2) on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "t = U.tensor_field(1, 2, name='T') ; print(t)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

As for vectors or 1-forms, the tensor's components with respect to the domain's default frame are set by means of square brackets:

" ] }, { "cell_type": "code", "execution_count": 200, "metadata": {}, "outputs": [], "source": [ "t[1,2,1] = 1 + x^2\n", "t[3,2,1] = x*y*z" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Unset components are zero:

" ] }, { "cell_type": "code", "execution_count": 201, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "T = (x^2 + 1) d/dx*dy*dx + x*y*z d/dz*dy*dx" ] }, "execution_count": 201, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t.display()" ] }, { "cell_type": "code", "execution_count": 202, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[[[0, 0, 0], [x^2 + 1, 0, 0], [0, 0, 0]],\n", " [[0, 0, 0], [0, 0, 0], [0, 0, 0]],\n", " [[0, 0, 0], [x*y*z, 0, 0], [0, 0, 0]]]" ] }, "execution_count": 202, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t[:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Display of the nonzero components:

" ] }, { "cell_type": "code", "execution_count": 203, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "T^x_yx = x^2 + 1 \n", "T^z_yx = x*y*z " ] }, "execution_count": 203, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t.display_comp()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Double square brackets return the component (still w.r.t. the default frame) as a scalar field, while single square brackets return the expression of this scalar field in terms of the domain's default coordinates:

" ] }, { "cell_type": "code", "execution_count": 204, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "U --> R\n", "(x, y, z) |--> x^2 + 1\n", "(r, th, ph) |--> r^2*cos(ph)^2*sin(th)^2 + 1" ] }, "execution_count": 204, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(t[[1,2,1]]) ; t[[1,2,1]].display()" ] }, { "cell_type": "code", "execution_count": 205, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x^2 + 1\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "x^2 + 1" ] }, "execution_count": 205, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(t[1,2,1]) ; t[1,2,1]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

A tensor field of type (1,2) maps a 3-tuple (1-form, vector field, vector field) to a scalar field:

" ] }, { "cell_type": "code", "execution_count": 206, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field T(omega,u,v) on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "T(omega,u,v): U --> R\n", " (x, y, z) |--> (x^2 + 1)*y^3*u_y(x, y, z) + (x^2 + 1)*y^2*u_y(x, y, z) - (x*y^2*u_y(x, y, z) + x*y*u_y(x, y, z))*z^2 + (x^4 + x^2)*y*u_y(x, y, z) + (x^2*y^2*u_y(x, y, z) + x^2*y*u_y(x, y, z))*z + (x^4 + x^2)*u_y(x, y, z)\n", " (r, th, ph) |--> (r^5*cos(ph)^2*sin(ph)*sin(th)^5 - ((cos(ph)^4 - cos(ph)^2)*r^5*cos(th) - r^4*cos(ph)^2)*sin(th)^4 + ((cos(ph)^3 - cos(ph))*r^5*cos(th)^2 + r^4*cos(ph)^2*cos(th)*sin(ph) + r^3*sin(ph))*sin(th)^3 - (r^4*cos(ph)*cos(th)^2*sin(ph) - r^2)*sin(th)^2)*u_y(r*cos(ph)*sin(th), r*sin(ph)*sin(th), r*cos(th))" ] }, "execution_count": 206, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(t(om, u, v)) ; t(om, u, v).display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

As for vectors and differential forms, the tensor components can be taken in any frame defined on the manifold:

" ] }, { "cell_type": "code", "execution_count": 207, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "r^2*cos(ph)^4*sin(ph)*sin(th)^5 + (cos(ph)^4 - cos(ph)^2)*r^3*sin(th)^6 - (cos(ph)^4 - cos(ph)^2)*r^3*sin(th)^4 + cos(ph)^2*sin(ph)*sin(th)^3" ] }, "execution_count": 207, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t[Y.frame(), 1,1,1, Y]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Tensor calculus

\n", "

The tensor product $\\otimes$ is denoted by `*`:

" ] }, { "cell_type": "code", "execution_count": 208, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "(0, 2)" ] }, "execution_count": 208, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.tensor_type() ; a.tensor_type()" ] }, { "cell_type": "code", "execution_count": 209, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tensor field v*A of type (1,2) on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "Tensor field v*A of type (1,2) on the Open subset U of the 3-dimensional differentiable manifold M" ] }, "execution_count": 209, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b = v*a ; print(b) ; b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The tensor product preserves the (anti)symmetries: since $A$ is a 2-form, it is antisymmetric with respect to its two arguments (positions 0 and 1); as a result, b is antisymmetric with respect to its last two arguments (positions 1 and 2):

" ] }, { "cell_type": "code", "execution_count": 210, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "no symmetry; antisymmetry: (0, 1)\n" ] } ], "source": [ "a.symmetries()" ] }, { "cell_type": "code", "execution_count": 211, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "no symmetry; antisymmetry: (1, 2)\n" ] } ], "source": [ "b.symmetries()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Standard tensor arithmetics is implemented:

" ] }, { "cell_type": "code", "execution_count": 212, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tensor field of type (1,2) on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "s = - t + 2*f* b ; print(s)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Tensor contractions are dealt with by the methods trace() and contract(): for instance, let us contract the tensor $T$ w.r.t. its first two arguments (positions 0 and 1), i.e. let us form the tensor $c$ of components $c_i = T^k_{\\ \\, k i}$:

" ] }, { "cell_type": "code", "execution_count": 213, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1-form on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "c = t.trace(0,1)\n", "print(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

An alternative to the writing trace(0,1) is to use the index notation to denote the contraction: the indices are given in a string inside the [] operator, with '^' in front of the contravariant indices and '_' in front of the covariant ones:

" ] }, { "cell_type": "code", "execution_count": 214, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1-form on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 214, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c1 = t['^k_ki']\n", "print(c1)\n", "c1 == c" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The contraction is performed on the repeated index (here k); the letter denoting the remaining index (here i) is arbitrary:

" ] }, { "cell_type": "code", "execution_count": 215, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 215, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t['^k_kj'] == c" ] }, { "cell_type": "code", "execution_count": 216, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 216, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t['^b_ba'] == c" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

It can even be replaced by a dot:

" ] }, { "cell_type": "code", "execution_count": 217, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 217, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t['^k_k.'] == c" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

LaTeX notations are allowed:

" ] }, { "cell_type": "code", "execution_count": 218, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 218, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t['^{k}_{ki}'] == c" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The contraction $T^i_{\\ j k} v^k$ of the tensor fields $T$ and $v$ is taken as follows (2 refers to the last index position of $T$ and 0 to the only index position of v):

" ] }, { "cell_type": "code", "execution_count": 219, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tensor field of type (1,1) on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "tv = t.contract(2, v, 0)\n", "print(tv)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Since 2 corresponds to the last index position of $T$ and 0 to the first index position of $v$, a shortcut for the above is

" ] }, { "cell_type": "code", "execution_count": 220, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tensor field of type (1,1) on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "tv1 = t.contract(v)\n", "print(tv1)" ] }, { "cell_type": "code", "execution_count": 221, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 221, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tv1 == tv" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Instead of contract(), the index notation, combined with the * operator, can be used to denote the contraction:

" ] }, { "cell_type": "code", "execution_count": 222, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 222, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t['^i_jk']*v['^k'] == tv" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The non-repeated indices can be replaced by dots:

" ] }, { "cell_type": "code", "execution_count": 223, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 223, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t['^._.k']*v['^k'] == tv" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Metric structures

\n", "

A Riemannian metric on the manifold $\\mathcal{M}$ is declared as follows:

" ] }, { "cell_type": "code", "execution_count": 224, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Riemannian metric g on the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "g = M.riemannian_metric('g')\n", "print(g)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

It is a symmetric tensor field of type (0,2):

" ] }, { "cell_type": "code", "execution_count": 225, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Free module T^(0,2)(M) of type-(0,2) tensors fields on the 3-dimensional differentiable manifold M" ] }, "execution_count": 225, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g.parent()" ] }, { "cell_type": "code", "execution_count": 226, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Free module T^(0,2)(M) of type-(0,2) tensors fields on the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "print(g.parent())" ] }, { "cell_type": "code", "execution_count": 227, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "symmetry: (0, 1); no antisymmetry\n" ] } ], "source": [ "g.symmetries()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The metric is initialized by its components with respect to some vector frame. For instance, using the default frame of $\\mathcal{M}$:

" ] }, { "cell_type": "code", "execution_count": 228, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "g = dx*dx + dy*dy + dz*dz" ] }, "execution_count": 228, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g[1,1], g[2,2], g[3,3] = 1, 1, 1\n", "g.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The components w.r.t. another vector frame are obtained as for any tensor field:

" ] }, { "cell_type": "code", "execution_count": 229, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "g = dr*dr + r^2 dth*dth + r^2*sin(th)^2 dph*dph" ] }, "execution_count": 229, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g.display(Y.frame(), Y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Of course, the metric acts on vector pairs:

" ] }, { "cell_type": "code", "execution_count": 230, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field g(u,v) on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "g(u,v): U --> R\n", " (x, y, z) |--> x*y*z*u_z(x, y, z) + y*u_x(x, y, z) - x*u_y(x, y, z) + u_x(x, y, z)\n", " (r, th, ph) |--> r^3*cos(ph)*cos(th)*sin(ph)*sin(th)^2*u_z(r*cos(ph)*sin(th), r*sin(ph)*sin(th), r*cos(th)) - r*cos(ph)*sin(th)*u_y(r*cos(ph)*sin(th), r*sin(ph)*sin(th), r*cos(th)) + (r*sin(ph)*sin(th) + 1)*u_x(r*cos(ph)*sin(th), r*sin(ph)*sin(th), r*cos(th))" ] }, "execution_count": 230, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u.display() ; v.display(); print(g(u,v)) ; g(u,v).display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The Levi-Civita connection associated to the metric $g$:

" ] }, { "cell_type": "code", "execution_count": 231, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Levi-Civita connection nabla_g associated with the Riemannian metric g on the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "Levi-Civita connection nabla_g associated with the Riemannian metric g on the 3-dimensional differentiable manifold M" ] }, "execution_count": 231, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nabla = g.connection() \n", "print(nabla) ; nabla" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The Christoffel symbols with respect to the manifold's default coordinates:

" ] }, { "cell_type": "code", "execution_count": 232, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[[[0, 0, 0], [0, 0, 0], [0, 0, 0]],\n", " [[0, 0, 0], [0, 0, 0], [0, 0, 0]],\n", " [[0, 0, 0], [0, 0, 0], [0, 0, 0]]]" ] }, "execution_count": 232, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nabla.coef()[:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The Christoffel symbols with respect to the coordinates $(r,\\theta,\\phi)$:

" ] }, { "cell_type": "code", "execution_count": 233, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[[[0, 0, 0], [0, -r, 0], [0, 0, -r*sin(th)^2]],\n", " [[0, 1/r, 0], [1/r, 0, 0], [0, 0, -cos(th)*sin(th)]],\n", " [[0, 0, 1/r], [0, 0, cos(th)/sin(th)], [1/r, cos(th)/sin(th), 0]]]" ] }, "execution_count": 233, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nabla.coef(Y.frame())[:, Y]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A nice view is obtained via the method `display()` (by default, only the nonzero connection coefficients are shown):" ] }, { "cell_type": "code", "execution_count": 234, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Gam^r_th,th = -r \n", "Gam^r_ph,ph = -r*sin(th)^2 \n", "Gam^th_r,th = 1/r \n", "Gam^th_th,r = 1/r \n", "Gam^th_ph,ph = -cos(th)*sin(th) \n", "Gam^ph_r,ph = 1/r \n", "Gam^ph_th,ph = cos(th)/sin(th) \n", "Gam^ph_ph,r = 1/r \n", "Gam^ph_ph,th = cos(th)/sin(th) " ] }, "execution_count": 234, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nabla.display(frame=Y.frame(), chart=Y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One may also use the method `christoffel_symbols_display()` of the metric, which (by default) displays only the non-redundant Christoffel symbols:" ] }, { "cell_type": "code", "execution_count": 235, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Gam^r_th,th = -r \n", "Gam^r_ph,ph = -r*sin(th)^2 \n", "Gam^th_r,th = 1/r \n", "Gam^th_ph,ph = -cos(th)*sin(th) \n", "Gam^ph_r,ph = 1/r \n", "Gam^ph_th,ph = cos(th)/sin(th) " ] }, "execution_count": 235, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g.christoffel_symbols_display(Y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The connection acting as a covariant derivative:

" ] }, { "cell_type": "code", "execution_count": 236, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tensor field nabla_g(v) of type (1,1) on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "nabla_g(v) = d/dx*dy - d/dy*dx + y*z d/dz*dx + x*z d/dz*dy + x*y d/dz*dz" ] }, "execution_count": 236, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nab_v = nabla(v)\n", "print(nab_v) ; nab_v.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Being a Levi-Civita connection, $\\nabla_g$ is torsion.free:

" ] }, { "cell_type": "code", "execution_count": 237, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tensor field of type (1,2) on the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "0" ] }, "execution_count": 237, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(nabla.torsion()) ; nabla.torsion().display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

In the present case, it is also flat:

" ] }, { "cell_type": "code", "execution_count": 238, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tensor field Riem(g) of type (1,3) on the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "Riem(g) = 0" ] }, "execution_count": 238, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(nabla.riemann()) ; nabla.riemann().display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Let us consider a non-flat metric, by changing $g_{rr}$ to $1/(1+r^2)$:

" ] }, { "cell_type": "code", "execution_count": 239, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "g = 1/(r^2 + 1) dr*dr + r^2 dth*dth + r^2*sin(th)^2 dph*dph" ] }, "execution_count": 239, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g[Y.frame(), 1,1, Y] = 1/(1+r^2)\n", "g.display(Y.frame(), Y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

For convenience, we change the default chart on the domain $U$ to Y=$(U,(r,\\theta,\\phi))$:

" ] }, { "cell_type": "code", "execution_count": 240, "metadata": {}, "outputs": [], "source": [ "U.set_default_chart(Y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

In this way, we do not have to specify Y when asking for coordinate expressions in terms of $(r,\\theta,\\phi)$:

" ] }, { "cell_type": "code", "execution_count": 241, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "g = 1/(r^2 + 1) dr*dr + r^2 dth*dth + r^2*sin(th)^2 dph*dph" ] }, "execution_count": 241, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g.display(Y.frame())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

We recognize the metric of the hyperbolic space $\\mathbb{H}^3$. Its expression in terms of the chart $(U,(x,y,z))$ is

" ] }, { "cell_type": "code", "execution_count": 242, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "g = (y^2 + z^2 + 1)/(x^2 + y^2 + z^2 + 1) dx*dx - x*y/(x^2 + y^2 + z^2 + 1) dx*dy - x*z/(x^2 + y^2 + z^2 + 1) dx*dz - x*y/(x^2 + y^2 + z^2 + 1) dy*dx + (x^2 + z^2 + 1)/(x^2 + y^2 + z^2 + 1) dy*dy - y*z/(x^2 + y^2 + z^2 + 1) dy*dz - x*z/(x^2 + y^2 + z^2 + 1) dz*dx - y*z/(x^2 + y^2 + z^2 + 1) dz*dy + (x^2 + y^2 + 1)/(x^2 + y^2 + z^2 + 1) dz*dz" ] }, "execution_count": 242, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g.display(X_U.frame(), X_U)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

A matrix view of the components may be more appropriate:

" ] }, { "cell_type": "code", "execution_count": 243, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[(y^2 + z^2 + 1)/(x^2 + y^2 + z^2 + 1) -x*y/(x^2 + y^2 + z^2 + 1) -x*z/(x^2 + y^2 + z^2 + 1)]\n", "[ -x*y/(x^2 + y^2 + z^2 + 1) (x^2 + z^2 + 1)/(x^2 + y^2 + z^2 + 1) -y*z/(x^2 + y^2 + z^2 + 1)]\n", "[ -x*z/(x^2 + y^2 + z^2 + 1) -y*z/(x^2 + y^2 + z^2 + 1) (x^2 + y^2 + 1)/(x^2 + y^2 + z^2 + 1)]" ] }, "execution_count": 243, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g[X_U.frame(), :, X_U]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

We extend these components, a priori defined only on $U$, to the whole manifold $\\mathcal{M}$, by demanding the same coordinate expressions in the frame associated to the chart X=$(\\mathcal{M},(x,y,z))$:

" ] }, { "cell_type": "code", "execution_count": 244, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "g = (y^2 + z^2 + 1)/(x^2 + y^2 + z^2 + 1) dx*dx - x*y/(x^2 + y^2 + z^2 + 1) dx*dy - x*z/(x^2 + y^2 + z^2 + 1) dx*dz - x*y/(x^2 + y^2 + z^2 + 1) dy*dx + (x^2 + z^2 + 1)/(x^2 + y^2 + z^2 + 1) dy*dy - y*z/(x^2 + y^2 + z^2 + 1) dy*dz - x*z/(x^2 + y^2 + z^2 + 1) dz*dx - y*z/(x^2 + y^2 + z^2 + 1) dz*dy + (x^2 + y^2 + 1)/(x^2 + y^2 + z^2 + 1) dz*dz" ] }, "execution_count": 244, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g.add_comp_by_continuation(X.frame(), U, X)\n", "g.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The following cell corrects a bug that has been introduced in SageMath 8.3 (it will be removed in SageMath 8.4):" ] }, { "cell_type": "code", "execution_count": 245, "metadata": {}, "outputs": [], "source": [ "if \"version 8.3\" in version():\n", " del g.inverse()._restrictions_graph[U]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The Levi-Civita connection is automatically recomputed, after the change in $g$:

" ] }, { "cell_type": "code", "execution_count": 246, "metadata": {}, "outputs": [], "source": [ "nabla = g.connection()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

In particular, the Christoffel symbols are different:

" ] }, { "cell_type": "code", "execution_count": 247, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Gam^x_xx = -(x*y^2 + x*z^2 + x)/(x^2 + y^2 + z^2 + 1) \n", "Gam^x_xy = x^2*y/(x^2 + y^2 + z^2 + 1) \n", "Gam^x_xz = x^2*z/(x^2 + y^2 + z^2 + 1) \n", "Gam^x_yy = -(x^3 + x*z^2 + x)/(x^2 + y^2 + z^2 + 1) \n", "Gam^x_yz = x*y*z/(x^2 + y^2 + z^2 + 1) \n", "Gam^x_zz = -(x^3 + x*y^2 + x)/(x^2 + y^2 + z^2 + 1) \n", "Gam^y_xx = -(y^3 + y*z^2 + y)/(x^2 + y^2 + z^2 + 1) \n", "Gam^y_xy = x*y^2/(x^2 + y^2 + z^2 + 1) \n", "Gam^y_xz = x*y*z/(x^2 + y^2 + z^2 + 1) \n", "Gam^y_yy = -(y*z^2 + (x^2 + 1)*y)/(x^2 + y^2 + z^2 + 1) \n", "Gam^y_yz = y^2*z/(x^2 + y^2 + z^2 + 1) \n", "Gam^y_zz = -(y^3 + (x^2 + 1)*y)/(x^2 + y^2 + z^2 + 1) \n", "Gam^z_xx = -(z^3 + (y^2 + 1)*z)/(x^2 + y^2 + z^2 + 1) \n", "Gam^z_xy = x*y*z/(x^2 + y^2 + z^2 + 1) \n", "Gam^z_xz = x*z^2/(x^2 + y^2 + z^2 + 1) \n", "Gam^z_yy = -(z^3 + (x^2 + 1)*z)/(x^2 + y^2 + z^2 + 1) \n", "Gam^z_yz = y*z^2/(x^2 + y^2 + z^2 + 1) \n", "Gam^z_zz = -(x^2 + y^2 + 1)*z/(x^2 + y^2 + z^2 + 1) " ] }, "execution_count": 247, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nabla.display(only_nonredundant=True)" ] }, { "cell_type": "code", "execution_count": 248, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Gam^r_r,r = -r/(r^2 + 1) \n", "Gam^r_th,th = -r^3 - r \n", "Gam^r_ph,ph = -(r^3 + r)*sin(th)^2 \n", "Gam^th_r,th = 1/r \n", "Gam^th_ph,ph = -cos(th)*sin(th) \n", "Gam^ph_r,ph = 1/r \n", "Gam^ph_th,ph = cos(th)/sin(th) " ] }, "execution_count": 248, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nabla.display(frame=Y.frame(), chart=Y, only_nonredundant=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The Riemann tensor is now

" ] }, { "cell_type": "code", "execution_count": 249, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tensor field Riem(g) of type (1,3) on the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "Riem(g) = -r^2 d/dr*dth*dr*dth + r^2 d/dr*dth*dth*dr - r^2*sin(th)^2 d/dr*dph*dr*dph + r^2*sin(th)^2 d/dr*dph*dph*dr + 1/(r^2 + 1) d/dth*dr*dr*dth - 1/(r^2 + 1) d/dth*dr*dth*dr - r^2*sin(th)^2 d/dth*dph*dth*dph + r^2*sin(th)^2 d/dth*dph*dph*dth + 1/(r^2 + 1) d/dph*dr*dr*dph - 1/(r^2 + 1) d/dph*dr*dph*dr + r^2 d/dph*dth*dth*dph - r^2 d/dph*dth*dph*dth" ] }, "execution_count": 249, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Riem = nabla.riemann()\n", "print(Riem) ; Riem.display(Y.frame())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Note that it can be accessed directely via the metric, without any explicit mention of the connection:

" ] }, { "cell_type": "code", "execution_count": 250, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 250, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g.riemann() is nabla.riemann()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The Ricci tensor is

" ] }, { "cell_type": "code", "execution_count": 251, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Field of symmetric bilinear forms Ric(g) on the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "Ric(g) = -2/(r^2 + 1) dr*dr - 2*r^2 dth*dth - 2*r^2*sin(th)^2 dph*dph" ] }, "execution_count": 251, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Ric = g.ricci()\n", "print(Ric) ; Ric.display(Y.frame())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The Weyl tensor is:

" ] }, { "cell_type": "code", "execution_count": 252, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tensor field C(g) of type (1,3) on the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "C(g) = 0" ] }, "execution_count": 252, "metadata": {}, "output_type": "execute_result" } ], "source": [ "C = g.weyl()\n", "print(C) ; C.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The Weyl tensor vanishes identically because the dimension of $\\mathcal{M}$ is 3.

\n", "

Finally, the Ricci scalar is

" ] }, { "cell_type": "code", "execution_count": 253, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field r(g) on the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "r(g): M --> R\n", " (x, y, z) |--> -6\n", "on U: (r, th, ph) |--> -6" ] }, "execution_count": 253, "metadata": {}, "output_type": "execute_result" } ], "source": [ "R = g.ricci_scalar()\n", "print(R) ; R.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

We recover the fact that $\\mathbb{H}^3$ is a Riemannian manifold of constant negative curvature.

\n", "\n", "

Tensor transformations induced by a metric

\n", "

The most important tensor transformation induced by the metric $g$ is the so-called musical isomorphism, or index raising and index lowering:

" ] }, { "cell_type": "code", "execution_count": 254, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tensor field T of type (1,2) on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "print(t)" ] }, { "cell_type": "code", "execution_count": 255, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "T = (r^2*cos(ph)^2*sin(th)^2 + 1) d/dx*dy*dx + r^3*cos(ph)*cos(th)*sin(ph)*sin(th)^2 d/dz*dy*dx" ] }, "execution_count": 255, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t.display()" ] }, { "cell_type": "code", "execution_count": 256, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "T = (x^2 + 1) d/dx*dy*dx + x*y*z d/dz*dy*dx" ] }, "execution_count": 256, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t.display(X_U.frame(), X_U)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Raising the last index of $T$ with $g$:

" ] }, { "cell_type": "code", "execution_count": 257, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tensor field of type (2,1) on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "s = t.up(g, 2)\n", "print(s)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Raising all the covariant indices of $T$ (i.e. those at the positions 1 and 2):

" ] }, { "cell_type": "code", "execution_count": 258, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tensor field of type (3,0) on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "s = t.up(g)\n", "print(s)" ] }, { "cell_type": "code", "execution_count": 259, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tensor field of type (0,3) on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "s = t.down(g)\n", "print(s)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Hodge duality

\n", "

The volume 3-form (Levi-Civita tensor) associated with the metric $g$ is

" ] }, { "cell_type": "code", "execution_count": 260, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3-form eps_g on the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "eps_g = 1/sqrt(x^2 + y^2 + z^2 + 1) dx/\\dy/\\dz" ] }, "execution_count": 260, "metadata": {}, "output_type": "execute_result" } ], "source": [ "epsilon = g.volume_form()\n", "print(epsilon) ; epsilon.display()" ] }, { "cell_type": "code", "execution_count": 261, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "eps_g = r^2*sin(th)/sqrt(r^2 + 1) dr/\\dth/\\dph" ] }, "execution_count": 261, "metadata": {}, "output_type": "execute_result" } ], "source": [ "epsilon.display(Y.frame())" ] }, { "cell_type": "code", "execution_count": 262, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field f on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "f: U --> R\n", " (x, y, z) |--> z^3 + y^2 + x\n", " (r, th, ph) |--> r^3*cos(th)^3 + r^2*sin(ph)^2*sin(th)^2 + r*cos(ph)*sin(th)" ] }, "execution_count": 262, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(f) ; f.display()" ] }, { "cell_type": "code", "execution_count": 263, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3-form *f on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "*f = (r^3*cos(th)^3 + r^2*sin(ph)^2*sin(th)^2 + r*cos(ph)*sin(th))/sqrt(r^2 + 1) dx/\\dy/\\dz" ] }, "execution_count": 263, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sf = f.hodge_dual(g)\n", "print(sf) ; sf.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

We check the classical formula $\\star f = f\\, \\epsilon_g$, or, more precisely, $\\star f = f\\, \\epsilon_g|_U$ (for $f$ is defined on $U$ only):

" ] }, { "cell_type": "code", "execution_count": 264, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 264, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sf == f * epsilon.restrict(U)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The Hodge dual of a 1-form is a 2-form:

" ] }, { "cell_type": "code", "execution_count": 265, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1-form omega on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "omega = r^2*sin(th)^2 dx + r*cos(th) dy + (r*cos(ph)*sin(th) - r*cos(th)) dz" ] }, "execution_count": 265, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(om) ; om.display()" ] }, { "cell_type": "code", "execution_count": 266, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2-form *omega on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "*omega = (r^4*cos(ph)*cos(th)*sin(th)^3 - r^3*cos(th)^3 - r*cos(th) + (r^3*(cos(ph) + sin(ph))*cos(th)^2 + r*cos(ph))*sin(th))/sqrt(r^2 + 1) dx/\\dy - (r^4*cos(ph)*sin(ph)*sin(th)^4 - r^3*cos(th)^2*sin(ph)*sin(th) + (cos(ph)*sin(ph) + sin(ph)^2)*r^3*cos(th)*sin(th)^2 + r*cos(th))/sqrt(r^2 + 1) dx/\\dz + (r^4*cos(ph)^2*sin(th)^4 - r^3*cos(ph)*cos(th)^2*sin(th) + ((cos(ph)^2 + cos(ph)*sin(ph))*r^3*cos(th) + r^2)*sin(th)^2)/sqrt(r^2 + 1) dy/\\dz" ] }, "execution_count": 266, "metadata": {}, "output_type": "execute_result" } ], "source": [ "som = om.hodge_dual(g)\n", "print(som) ; som.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The Hodge dual of a 2-form is a 1-form:

" ] }, { "cell_type": "code", "execution_count": 267, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2-form A on the Open subset U of the 3-dimensional differentiable manifold M\n" ] } ], "source": [ "print(a)" ] }, { "cell_type": "code", "execution_count": 268, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1-form *A on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "*A = (3*r^5*cos(th)^5 + 3*r^3*cos(th)^3 + (3*r^6*cos(ph)*cos(th)^2*sin(ph) - 2*r^5*cos(ph)*cos(th)*sin(ph) - 2*r^4*cos(ph)*sin(ph)^3)*sin(th)^4 + (2*r^4*cos(th)*sin(ph)^3 + (sin(ph)^3 - sin(ph))*r^3)*sin(th)^3 + (3*r^5*cos(th)^3*sin(ph)^2 - 2*r^4*cos(ph)*cos(th)^2*sin(ph) + r^3*cos(ph)*cos(th)*sin(ph) - 2*r^2*cos(ph)*sin(ph))*sin(th)^2 + (2*r^4*cos(th)^3*sin(ph) + r^3*cos(ph)*cos(th)^2 + 2*r^2*cos(th)*sin(ph))*sin(th))/sqrt(r^2 + 1) dx - (r^3*cos(th)^3 + (3*r^6*cos(ph)^2*cos(th)^2 - 2*(cos(ph)^2 - 1)*r^5*cos(th) + 2*(cos(ph)^4 - cos(ph)^2)*r^4)*sin(th)^4 - (r^3*cos(ph)^3 + 2*(cos(ph)^3 - cos(ph))*r^4*cos(th))*sin(th)^3 + (3*r^6*cos(th)^4 + 3*r^5*cos(ph)*cos(th)^3*sin(ph) + r^3*cos(ph)^2*cos(th) + 3*r^4*cos(th)^2)*sin(th)^2 + r*cos(th) - (r^3*(cos(ph) + sin(ph))*cos(th)^2 + r*cos(ph))*sin(th))/sqrt(r^2 + 1) dy + (2*r^5*sin(ph)*sin(th)^5 + (3*r^6*cos(th)^3*sin(ph) + 2*r^4*cos(ph)^2*cos(th)*sin(ph) + 2*r^3*sin(ph))*sin(th)^3 - (2*r^4*cos(ph)*cos(th)^2*sin(ph) + (cos(ph)*sin(ph) + 1)*r^3*cos(th))*sin(th)^2 - r*cos(th) - (3*r^5*cos(ph)*cos(th)^4 - r^3*cos(th)^2*sin(ph))*sin(th))/sqrt(r^2 + 1) dz" ] }, "execution_count": 268, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sa = a.hodge_dual(g)\n", "print(sa) ; sa.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Finally, the Hodge dual of a 3-form is a 0-form:

" ] }, { "cell_type": "code", "execution_count": 269, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3-form dA on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "dA = (-2*(3*r^3*cos(th)^2*sin(ph) + r*sin(ph))*sin(th) - 1) dx/\\dy/\\dz" ] }, "execution_count": 269, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(da) ; da.display()" ] }, { "cell_type": "code", "execution_count": 270, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scalar field *dA on the Open subset U of the 3-dimensional differentiable manifold M\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "*dA: U --> R\n", " (x, y, z) |--> -(6*y*z^2 + 2*y + 1)*sqrt(x^2 + y^2 + z^2 + 1)\n", " (r, th, ph) |--> -sqrt(r^2 + 1)*(2*(3*r^3*cos(th)^2*sin(ph) + r*sin(ph))*sin(th) + 1)" ] }, "execution_count": 270, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sda = da.hodge_dual(g)\n", "print(sda) ; sda.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

In dimension 3 and for a Riemannian metric, the Hodge star is idempotent:

" ] }, { "cell_type": "code", "execution_count": 271, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 271, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sf.hodge_dual(g) == f" ] }, { "cell_type": "code", "execution_count": 272, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 272, "metadata": {}, "output_type": "execute_result" } ], "source": [ "som.hodge_dual(g) == om" ] }, { "cell_type": "code", "execution_count": 273, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 273, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sa.hodge_dual(g) == a" ] }, { "cell_type": "code", "execution_count": 274, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 274, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sda.hodge_dual(g) == da" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Getting help

\n", "

To get the list of functions (methods) that can be called on a object, type the name of the object, followed by a dot and the TAB key, e.g.

\n", "

sa.

\n", "

To get information on an object or a method, use the question mark:

" ] }, { "cell_type": "code", "execution_count": 275, "metadata": {}, "outputs": [], "source": [ "nabla?" ] }, { "cell_type": "code", "execution_count": 276, "metadata": {}, "outputs": [], "source": [ "g.ricci_scalar?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Using a double question mark leads directly to the Python source code (SageMath is open source, isn't it?)

" ] }, { "cell_type": "code", "execution_count": 277, "metadata": {}, "outputs": [], "source": [ "g.ricci_scalar??" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Going further

\n", "

Have a look at the examples on SageManifolds page, especially the 2-dimensional sphere example for usage on a non-parallelizable manifold (each scalar field has to be defined in at least two coordinate charts, the module $\\mathfrak{X}(\\mathcal{M})$ is no longer free and each tensor field has to be defined in at least two vector frames).

" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "SageMath 8.3", "language": "", "name": "sagemath" }, "language": "python", "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.15" } }, "nbformat": 4, "nbformat_minor": 1 }