{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Mixed Forms and Characteristic Classes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This Jupyter notebook illustrates SageMath's functionalities regarding mixed differential forms and characteristic classes. The involved tools have been developed through the [SageManifolds](https://sagemanifolds.obspm.fr) project. \n", "\n", "**Author:** *Michael Jung*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A version of SageMath at least equal to 9.0 is required to run this notebook:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'SageMath version 9.1.beta6, Release Date: 2020-03-01'" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "version()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First we set up the notebook to display math formulas using LaTeX formatting:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "%display latex" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Mixed Differential Forms" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We briefly demonstrate the capabilities of our implementation, and start by declaring the manifold $M=\\mathbb{R}^2$:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "M = Manifold(2, 'R^2', latex_name=r'\\mathbb{R}^2')\n", "X. = M.chart()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We define the corresponding spaces of differential forms:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Algebra of differentiable scalar fields on the 2-dimensional differentiable manifold R^2\n", "Free module Omega^1(R^2) of 1-forms on the 2-dimensional differentiable manifold R^2\n", "Free module Omega^2(R^2) of 2-forms on the 2-dimensional differentiable manifold R^2\n" ] } ], "source": [ "Omega0 = M.diff_form_module(0); print(Omega0)\n", "Omega1 = M.diff_form_module(1); print(Omega1)\n", "Omega2 = M.diff_form_module(2); print(Omega2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The algebra of mixed forms is returned by a simple command:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Graded algebra Omega^*(R^2) of mixed differential forms on the 2-dimensional differentiable manifold R^2\n" ] } ], "source": [ "Omega = M.mixed_form_algebra(); print(Omega)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It belongs to the category of graded algebras over the symbolic ring:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Category of graded algebras over Symbolic Ring\n" ] } ], "source": [ "print(Omega.category())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Before proceeding with mixed forms, let us first declare some differential forms:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "f = M.scalar_field(name='f')\n", "omega1 = M.diff_form(1, name='omega_1', latex_name=r'\\omega_1')\n", "omega2 = M.diff_form(2, name='omega_2', latex_name=r'\\omega_2')\n", "eta = M.diff_form(1, name='eta', latex_name=r'\\eta')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the next step, we provide some expressions in local coordinates:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "f.set_expr(x^2)\n", "omega1[:] = y, 2*x\n", "omega2[0,1] = 4*x^3\n", "eta[:] = x, y" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "f: R^2 --> R\n", " (x, y) |--> x^2" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.display()" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "omega_1 = y dx + 2*x dy" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "omega1.display()" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "omega_2 = 4*x^3 dx/\\dy" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "omega2.display()" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "eta = x dx + y dy" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "eta.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The category framework of `Sage` captures the entire setup:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "all([f in Omega0,\n", " f in Omega,\n", " omega1 in Omega1,\n", " omega1 in Omega,\n", " omega2 in Omega2,\n", " omega2 in Omega])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, let us define a mixed form:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Mixed differential form A on the 2-dimensional differentiable manifold R^2\n" ] } ], "source": [ "A = M.mixed_form(name='A'); print(A)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It shall consist of the differential forms $f, \\omega_1, \\omega_2$. The forms are assigned by using index operations:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "A = f + omega_1 + omega_2" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A[:] = [f,omega1,omega2]; A.display()" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "A = [x^2] + [y dx + 2*x dy] + [4*x^3 dx/\\dy]" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A.display_expansion()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we can see, the output is sorted by degree. Notice that the forms stored in `A` are given by the very same instances we declared beforehand:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "all([A[0] is f,\n", " A[1] is omega1,\n", " A[2] is omega2])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If that behavior is unwanted, a copy can be made which has the very same expressions in local coordinates but has stored entirely new instances:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "False" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Aclone = A.copy()\n", "any(Aclone[k] is A[k] for k in Omega.irange())" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "all(Aclone[k] == A[k] for k in Omega.irange())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us perform some computations and define another mixed form:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "B = [2] + [x dx + y dy] + [0]" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "B = M.mixed_form([2,eta,0], name='B'); B.display_expansion()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The multiplication is executed degree wise:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "all((A * B)[k] == sum(A[j].wedge(B[k - j])\n", " for j in range(k + 1))\n", " for k in Omega.irange())" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "A/\\B = [2*x^2] + [(x^3 + 2*y) dx + (x^2*y + 4*x) dy] + [(8*x^3 - 2*x^2 + y^2) dx/\\dy]" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(A * B).display_expansion()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This particular example is also convenient to demonstrate that the multiplication given by the wedge product is in general neither commutative nor anticommutative:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "B/\\A = [2*x^2] + [(x^3 + 2*y) dx + (x^2*y + 4*x) dy] + [(8*x^3 + 2*x^2 - y^2) dx/\\dy]" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(B * A).display_expansion()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, let us compute the exterior derivative:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "dA = [0] + [2*x dx] + [dx/\\dy]" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dA = A.exterior_derivative(); dA.display_expansion()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Characteristic Classes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Chern Character over Minkowski Space" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We want to exemplify the usage of characteristic classes within Sage by computing the Chern character form $\\mathrm{ch}(E, \\nabla^E)$ on a complex trivial line bundle $E$ over the 2-dimensional Minkowski space $M$ equipped with a bundle connection $\\nabla^E$. We start with the general setup:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Differentiable complex vector bundle E -> M of rank 1 over the base space 2-dimensional Lorentzian manifold M\n" ] } ], "source": [ "M = Manifold(2, 'M', structure='Lorentzian')\n", "X. = M.chart()\n", "E = M.vector_bundle(1, 'E', field='complex'); print(E)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To trivialize the vector bundle $E$, we fix a global frame $e$:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "e = E.local_frame('e') # trivialize" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us declare an $\\mathrm{U}(1)$-connection $\\nabla^E$ on $E$ given by an electromagnetic potential $A(t)$:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "nab = E.bundle_connection('nabla^E', latex_name=r'\\nabla^E')\n", "A = function('A')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The corresponding connection form $\\omega$ turns out as:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "omega = I*A(t) dx" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "omega = M.one_form(name='omega', latex_name=r'\\omega')\n", "omega[1] = I*A(t)\n", "omega.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us put this into the connection:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [], "source": [ "nab.set_connection_form(0, 0, omega)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that the Chern character $\\mathrm{ch}(E)$ is already predefined in the system. We can get it by the following command:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Characteristic class ch of additive type associated to e^x on the Differentiable complex vector bundle E -> M of rank 1 over the base space 2-dimensional Lorentzian manifold M\n" ] } ], "source": [ "ch = E.characteristic_class('ChernChar'); print(ch)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The computation of the corresponding Chern character form $\\mathrm{ch}(E,\\nabla^E)$ can be invoked by the method \\texttt{get\\_form}:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "ch(E, nabla^E) = [1] + [0] + [1/2*d(A)/dt/pi dt/\\dx]" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ch_form = ch.get_form(nab)\n", "ch_form.display_expansion()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can see that the resulting 2-form coincides with the Faraday tensor divided by $2 \\pi$ as expected." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example: Chern Class of the Tautological Line Bundle" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We start our computation by initializing the complex projective space as 2-dimensional real manifold with coordinates on $U:= \\mathbb{CP}^1 \\setminus \\left\\{ [1:0] \\right\\}$:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "M = Manifold(2, 'CP^1', start_index=1)\n", "U = M.open_subset('U')\n", "c_cart. = U.chart() # [1:x+I*y]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For the sake of convenience, we additionally declare the complex coordinates $z$ and $\\bar{z}$ on $U$:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "z = x + I*y\n", "zbar = x - I*y" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c_comp. = U.chart(r'z:z zbar:\\bar{z}')\n", "cart_to_comp = c_cart.transition_map(c_comp, (x+I*y, x-I*y))\n", "cart_to_comp.display()" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "x = 1/2*z + 1/2*zbar\n", "y = -1/2*I*z + 1/2*I*zbar" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "comp_to_cart = cart_to_comp.inverse()\n", "comp_to_cart.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, we are ready to construct the tautological line bundle $\\gamma_1$:" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [], "source": [ "E = M.vector_bundle(1, 'gamma_1',\n", " latex_name=r'\\gamma_1',\n", " field='complex')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Furthermore we declare a local frame $e$ on $U$ naturally given by $[z:1] \\mapsto \\left(\\begin{smallmatrix} z \\\\ 1 \\end{smallmatrix}\\right)$:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [], "source": [ "e = E.local_frame('e', domain=U)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To compute the Chern class, we still need a connection. The tautological line bundle inherits a Hermitian metric from the overlying trivial bundle $\\mathbb{C}^2 \\times \\mathbb{CP}^1$:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [], "source": [ "nab = E.bundle_connection('nabla', latex_name=r'\\nabla')\n", "omega = U.one_form(name='omega')\n", "omega[c_comp.frame(), 1, c_comp] = zbar/(1+z*zbar)\n", "nab.set_connection_form(1, 1, omega, frame=e)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is time to initialize $c(\\gamma_1)$. Fortunately `Sage` already knows the Chern class:" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Characteristic class c of multiplicative type associated to x + 1 on the Differentiable complex vector bundle gamma_1 -> CP^1 of rank 1 over the base space 2-dimensional differentiable manifold CP^1\n" ] } ], "source": [ "c = E.characteristic_class('Chern'); print(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let the machinery do its work:" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "c(gamma_1, nabla) = [1] + [0] + [1/2*I/(pi + pi*z^2*zbar^2 + 2*pi*z*zbar) dz/\\dzbar]" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c_form = c.get_form(nab)\n", "c_form.display_expansion(c_comp.frame(), chart=c_comp)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since this particular representation is defined outside a set of measure zero, we can compute its integral over $\\mathbb{CP}^1$ in real coordinates:" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "1" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "integrate(integrate(c_form[2][[1,2]].expr(c_cart), x, -infinity, infinity).full_simplify(), y, -infinity, infinity)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The result shows that $c_1(\\gamma_1)$ generates the second integer cohomology $H^2(\\mathbb{CP}^1, \\mathbb{Z})$." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Euler Class of $\\mathbb{S}^2$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this example, we want to compute the Euler class of the 2-sphere $\\mathbb{S}^2 \\subset \\mathbb{R}^3$. As usual, we cover $\\mathbb{S}^2$ by two parallelizable open subsets $U:=\\mathbb{S}^2 \\setminus \\{(0,0,1)\\}$ and $V:=\\mathbb{S}^2 \\setminus \\{(0,0,-1)\\}$ for which the point $(0,0,1)$ is identified with the north pole. We state stereographic coordinates in `Sage`: " ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [], "source": [ "M = Manifold(2, name='S^2', latex_name=r'\\mathbb{S}^2',\n", " structure='Riemannian', start_index=1)\n", "U = M.open_subset('U') ; V = M.open_subset('V')\n", "M.declare_union(U,V) # M is the union of U and V\n", "stereoN. = U.chart()\n", "stereoS. = V.chart(\"xp:x' yp:y'\")\n", "N_to_S = stereoN.transition_map(stereoS,\n", " (x/(x^2+y^2), y/(x^2+y^2)),\n", " intersection_name='W',\n", " restrictions1= x^2+y^2!=0,\n", " restrictions2= xp^2+yp^2!=0)\n", "S_to_N = N_to_S.inverse()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next we define the tangent bundle and its local frames induced by the charts:" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [], "source": [ "eU = stereoN.frame(); eV = stereoS.frame()\n", "TM = M.tangent_bundle()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Euler class is also one of the predefined classes. Thus, we can easily get it from the tangent bundle's instance:" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Characteristic class e of Pfaffian type associated to x on the Tangent bundle TS^2 over the 2-dimensional Riemannian manifold S^2\n" ] } ], "source": [ "e_class = TM.characteristic_class('Euler'); print(e_class)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To compute a form representing the Euler class, we need to state a suitable connection first. Here we want to use the Levi-Civita connection induced by the standard metric. This is simply given by the pullback of the Euclidean scalar product of the ambient space $\\mathbb{R}^3$ along the canonical embedding $\\iota: \\mathbb{S}^2 \\hookrightarrow \\mathbb{R}^3$. Let us define the ambient space $\\mathbb{R}^3$ and its Euclidean scalar product $h$:" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "h = dX*dX + dY*dY + dZ*dZ" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "E = Manifold(3, 'R^3', latex_name=r'\\mathbb{R}^3', start_index=1)\n", "cart. = E.chart()\n", "h = E.metric('h')\n", "h[1,1], h[2,2], h[3, 3] = 1, 1, 1\n", "h.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On that account, we declare the embedding $\\iota: \\mathbb{S}^2 \\hookrightarrow \\mathbb{R}^3$ in stereographic coordinates when one considers its projection from the north pole $(0, 0, 1)$ to the equatorial plane $Z=0$:" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "iota: S^2 --> R^3\n", "on U: (x, y) |--> (X, Y, Z) = (2*x/(x^2 + y^2 + 1), 2*y/(x^2 + y^2 + 1), -(x^2 + y^2 - 1)/(x^2 + y^2 + 1))\n", "on V: (xp, yp) |--> (X, Y, Z) = (2*xp/(xp^2 + yp^2 + 1), 2*yp/(xp^2 + yp^2 + 1), (xp^2 + yp^2 - 1)/(xp^2 + yp^2 + 1))" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "iota = M.diff_map(E, {(stereoN, cart):\n", " [2*x/(1+x^2+y^2), 2*y/(1+x^2+y^2),\n", " (1-x^2-y^2)/(1+x^2+y^2)],\n", " (stereoS, cart):\n", " [2*xp/(1+xp^2+yp^2), 2*yp/(1+xp^2+yp^2),\n", " (xp^2+yp^2-1)/(1+xp^2+yp^2)]},\n", " name='iota', latex_name=r'\\iota')\n", "iota.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can define the standard metric $g$ on $\\mathbb{S}^2$ by setting it as the pullback metric $\\iota^*h$:" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "g = 4/(x^2 + y^2 + 1)^2 dx*dx + 4/(x^2 + y^2 + 1)^2 dy*dy" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g = M.metric()\n", "g.set(iota.pullback(h))\n", "g[1,1].factor(); g[2,2].factor() # simplifications\n", "g.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The corresponding Levi-Civita connection is computed automatically:" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [], "source": [ "nab = g.connection()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since we have found the desired Levi-Civita connection, we want to compute the associated curvature forms and store them in a `Python` list:" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [], "source": [ "cmatrix_U = [[nab.curvature_form(i,j,eU) for j in TM.irange()]\n", " for i in TM.irange()]\n", "cmatrix_V = [[nab.curvature_form(i,j,eV) for j in TM.irange()]\n", " for i in TM.irange()]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Fortunately, the curvature form matrices are already skew-symmetric:" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "curvature (1,1) of connection nabla_g w.r.t. Coordinate frame (U, (d/dx,d/dy)) = 0" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "curvature (1,2) of connection nabla_g w.r.t. Coordinate frame (U, (d/dx,d/dy)) = 4/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dx/\\dy" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "curvature (2,1) of connection nabla_g w.r.t. Coordinate frame (U, (d/dx,d/dy)) = -4/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dx/\\dy" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "curvature (2,2) of connection nabla_g w.r.t. Coordinate frame (U, (d/dx,d/dy)) = 0" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "for i in range(TM.rank()):\n", " for j in range(TM.rank()):\n", " show(cmatrix_U[i][j].display())" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "curvature (1,1) of connection nabla_g w.r.t. Coordinate frame (V, (d/dxp,d/dyp)) = 0" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "curvature (1,2) of connection nabla_g w.r.t. Coordinate frame (V, (d/dxp,d/dyp)) = 4/(xp^4 + yp^4 + 2*(xp^2 + 1)*yp^2 + 2*xp^2 + 1) dxp/\\dyp" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "curvature (2,1) of connection nabla_g w.r.t. Coordinate frame (V, (d/dxp,d/dyp)) = -4/(xp^4 + yp^4 + 2*(xp^2 + 1)*yp^2 + 2*xp^2 + 1) dxp/\\dyp" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "curvature (2,2) of connection nabla_g w.r.t. Coordinate frame (V, (d/dxp,d/dyp)) = 0" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "for i in range(TM.rank()):\n", " for j in range(TM.rank()):\n", " show(cmatrix_V[i][j].display())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Hence we can put them into a dictionary and apply the algorithm:" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "e(TS^2, nabla_g) = [0] + [0] + [2/(pi + pi*x^4 + pi*y^4 + 2*pi*x^2 + 2*(pi + pi*x^2)*y^2) dx/\\dy]" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cmatrices = {eU: cmatrix_U, eV: cmatrix_V}\n", "e_class_form = e_class.get_form(nab, cmatrices)\n", "e_class_form.display_expansion()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We want to compute the Euler characteristic of $\\mathbb{S}^2$ now. This can be achieved by integrating the top form over $\\mathbb{S}^2$. But since $U$ and $\\mathbb{S}^2$ differ only by a point and therefore a set of measure zero, it is enough to integrate over the subset $U$:" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "2" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "integrate(integrate(e_class_form[2][[1,2]].expr(), x, -infinity, infinity).simplify_full(), y, -infinity, infinity)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We have eventually obtained the Euler characteristic of $\\mathbb{S}^2$." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### $\\hat{A}$-Class of Lorentzian Foliation of Berger Spheres" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We consider the space of unit quaternions $\\mathbb{S}^3 \\subset \\mathbb{R}^4 \\cong \\mathbb{H}$, where $\\mathbb{H}$ is endowed with the canonical basis $(\\mathbf{1}, \\mathbf{i}, \\mathbf{j}, \\mathbf{k})$. It turns out that $\\mathbb{S}^3$ admits a global frame $(\\varepsilon_1, \\varepsilon_2, \\varepsilon_3)$ so that we observe $\\mathbb{S}^3$ to be a parallelizable manifold.\n", "\n", "We introduce the following smooth family of so-called *Berger metrics*:\n", "\\begin{align*}\t\n", "\tg_t = a(t)^{2} \\; \\varepsilon^{1}\\otimes \\varepsilon^{1} +\\varepsilon^{2}\\otimes \\varepsilon^{2} +\\varepsilon^{3}\\otimes \\varepsilon^{3}.\n", "\\end{align*}\n", "\n", "This family can be used to define a globally hyperbolic manifold $M=\\mathbb{R} \\times \\mathbb{S}^3$ equipped with the Lorentzian metric $g = - {\\mathrm{d} t}^2 + g_t$ and hence foliated by Berger spheres.\n", "\n", "In the following we compute the $\\hat{A}$-form of the corresponding Levi-Civita connection $\\nabla_g$. We start the computation by declaring the Lorentzian manifold first:" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4-dimensional Lorentzian manifold M\n" ] } ], "source": [ "M = Manifold(4, 'M', structure='Lorentzian'); print(M)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We cover $M$ by two open subsets defined as $U := \\mathbb{R} \\times \\left( \\mathbb{S}^3 \\setminus \\{ -\\mathbf{1} \\} \\right)$ and $V := \\mathbb{R} \\times \\left( \\mathbb{S}^3 \\setminus \\{ \\mathbf{1} \\} \\right)$:" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [], "source": [ "U = M.open_subset('U'); V = M.open_subset('V')\n", "M.declare_union(U,V)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We need to impose coordinates on $M$ and use stereographic projections with respect to the foliated 3-sphere:" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "tp = t\n", "xp = x/(x^2 + y^2 + z^2)\n", "yp = y/(x^2 + y^2 + z^2)\n", "zp = z/(x^2 + y^2 + z^2)" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "stereoN. = U.chart()\n", "stereoS. = V.chart(\"tp:t' xp:x' yp:y' zp:z'\")\n", "N_to_S = stereoN.transition_map(stereoS,\n", " (t, x/(x^2+y^2+z^2),\n", " y/(x^2+y^2+z^2),\n", " z/(x^2+y^2+z^2)),\n", " intersection_name='W',\n", " restrictions1= x^2+y^2+z^2!=0,\n", " restrictions2= xp^2+yp^2+zp^2!=0)\n", "W = U.intersection(V)\n", "S_to_N = N_to_S.inverse()\n", "N_to_S.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "From above, we know that $M$ admits a global frame $(\\varepsilon_0, \\varepsilon_1, \\varepsilon_2, \\varepsilon_3)$:" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Vector frame (U, (E_0,E_1,E_2,E_3))" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "E = M.vector_frame('E', latex_symbol=r'\\varepsilon')\n", "E_U = E.restrict(U); E_U" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The vector field $\\varepsilon_0$ is simply given by $\\frac{\\partial}{\\partial t}$. To obtain the global vector frame $(\\varepsilon_1, \\varepsilon_2, \\varepsilon_3)$ on $\\mathbb{S}^3$ in stereographic coordinates, a computation within `Sage` is performed in the [this](https://nbviewer.jupyter.org/github/sagemanifolds/SageManifolds/blob/master/Notebooks/SM_sphere_S3_vectors.ipynb) Jupyter-Notebook. This is done by embedding $\\mathbb{S}^3$ into $\\mathbb{R}^4 \\cong \\mathbb{H}$, endowing it with the quaternionic structure. This eventually leads to:" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [], "source": [ "E_U[0][:] = [1,0,0,0]\n", "E_U[1][:] = [0, (x^2-y^2-z^2+1)/2, x*y+z, x*z-y]\n", "E_U[2][:] = [0, x*y-z, (1-x^2+y^2-z^2)/2, x+y*z] \n", "E_U[3][:] = [0, x*z+y, y*z-x, (1-x^2-y^2+z^2)/2]" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "E_0 = d/dt" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "E_1 = (1/2*x^2 - 1/2*y^2 - 1/2*z^2 + 1/2) d/dx + (x*y + z) d/dy + (x*z - y) d/dz" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "E_2 = (x*y - z) d/dx + (-1/2*x^2 + 1/2*y^2 - 1/2*z^2 + 1/2) d/dy + (y*z + x) d/dz" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "E_3 = (x*z + y) d/dx + (y*z - x) d/dy + (-1/2*x^2 - 1/2*y^2 + 1/2*z^2 + 1/2) d/dz" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "for i in M.irange():\n", " show(E_U[i].display())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To ensure evaluations in this particular frame, we must communicate the change-of-frame formula to `Sage`:" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [], "source": [ "P = U.automorphism_field()\n", "for i in M.irange():\n", " for j in M.irange():\n", " P[j,i] = E_U[i][j]" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [], "source": [ "U.set_change_of_frame(stereoN.frame(), E_U, P)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The subset $U$ differs from $M$ only by a one dimensional slit, and is therefore dense in $M$. As we know that $\\left(\\varepsilon_{0},\\varepsilon_{1},\\varepsilon_{2},\\varepsilon_{3}\\right)$ defines a \\emph{global} frame, its components can be easily and uniquely extended to all of $M$. For this, we use the method `add_comp_by_continuation`:" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [], "source": [ "for i in M.irange():\n", " E[i].add_comp_by_continuation(stereoS.frame(), W)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And again, we declare the change of frame:" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [], "source": [ "P = V.automorphism_field()\n", "for i in M.irange():\n", " for j in M.irange():\n", " P[j,i] = E.restrict(V)[i][j]" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [], "source": [ "V.set_change_of_frame(stereoS.frame(), E.restrict(V), P)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In order to reduce the computation time, we examine the $\\hat{A}$-class on the open subset $U \\subset M$ first. The final result can be obtained by continuation. For this purpose we define the tangent bundle over $U$:" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tangent bundle TU over the Open subset U of the 4-dimensional Lorentzian manifold M\n" ] } ], "source": [ "TU = U.tangent_bundle(); print(TU)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that the $\\hat{A}$-class is already predefined:" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Characteristic class A^ of multiplicative type associated to 1/2*sqrt(x)/sinh(1/2*sqrt(x)) on the Tangent bundle TU over the Open subset U of the 4-dimensional Lorentzian manifold M" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = TU.characteristic_class('AHat'); A" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Its holomorphic function is given by:" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "1/2*sqrt(x)/sinh(1/2*sqrt(x))" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A.function()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We are ready to define the Berger metric, at least on the subset $U$:" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [], "source": [ "a = function('a')" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "g = -E^0*E^0 + a(t)^2 E^1*E^1 + E^2*E^2 + E^3*E^3" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g = U.metric()\n", "g.add_comp(E_U)[0, 0] = - 1\n", "g.add_comp(E_U)[1, 1] = a(t)^2\n", "g.add_comp(E_U)[2, 2] = 1\n", "g.add_comp(E_U)[3, 3] = 1\n", "g.display(E_U)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The corresponding connection is automatically computed by `Sage`:" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Levi-Civita connection nabla_g associated with the Lorentzian metric g on the Open subset U of the 4-dimensional Lorentzian manifold M" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nab = g.connection(); nab" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, we perform the computation of the $\\hat{A}$-form with respect to this connection $\\nabla_g$:" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "A^(TU, nabla_g) = [1] + [0] + [0] + [0] + [1/24*(4*(a(t)^3 - a(t))*d(a)/dt - d(a)/dt*d^2(a)/dt^2)/pi^2 E^0/\\E^1/\\E^2/\\E^3]" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A_form = A.get_form(nab) # long time\n", "A_form.display_expansion(E_U, stereoN)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To attain $\\hat{A}(TM, \\nabla_g)$ in all given coordinates, we still have to extend the result onto $M$. With respect to the global frame $(\\varepsilon_0, \\varepsilon_1,\\varepsilon_2,\\varepsilon_3)$, the form $\\hat{A}(TU, \\nabla_g)$ only depends on the global coordinate $t$. This makes the continuation trivial. Besides, for the most part, one is interested in characteristic forms outside a set of measure zero. Hence, we terminate our calculation at this point." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "SageMath 9.1.beta6", "language": "sage", "name": "sagemath" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" } }, "nbformat": 4, "nbformat_minor": 2 }