{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Real projective plane $\\mathbb{RP}^2$\n", "\n", "This notebook demonstrates some capabilities of SageMath about differentiable manifolds on the example of real projective plane. The corresponding tools have been developed within\n", "the [SageManifolds](https://sagemanifolds.obspm.fr) project (version 1.3, as included in SageMath 8.3).\n", "\n", "Click [here](https://raw.githubusercontent.com/sagemanifolds/SageManifolds/master/Worksheets/v1.3/SM_projective_plane.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`\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*NB:* a version of SageMath at least equal to 7.5 is required to run this worksheet:" ] }, { "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": [ "We also define a viewer for 3D plots (use `'threejs'` or `'jmol'` for interactive 3D graphics):" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "viewer3D = 'threejs' # must be 'threejs', 'jmol', 'tachyon' or None (default)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Constructing the manifold\n", "We start by declaring the real projective plane as a 2-dimensional differentiable manifold:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "2-dimensional differentiable manifold RP^2" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "RP2 = Manifold(2, 'RP^2', r'\\mathbb{RP}^2') ; RP2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Then we provide $\\mathbb{RP}^2$ with some atlas. A minimal atlas on $\\mathbb{RP}^2$ must have at least three charts. Such an atlas is easy to infer from the common interpretation of $\\mathbb{RP}^2$ as the set of lines of $\\mathbb{R}^3$ passing through the origin $(x,y,z)=(0,0,0)$. Let $U_1$ be the subset of lines that are not contained in the plane $z=0$; this is an open set of $\\mathbb{RP}^2$, so that we declare it as:

" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Open subset U_1 of the 2-dimensional differentiable manifold RP^2" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "U1 = RP2.open_subset('U_1') ; U1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Any line in $U_1$ is uniquely determined by its intersection with the plane $z=1$. The Cartesian coordinates $(x,y,1)$ of the intersection point lead to an obvious coordinate system $(x_1,y_1)$ on $U_1$ by setting $(x_1,y_1)=(x,y)$:

" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Chart (U_1, (x1, y1))" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X1. = U1.chart() ; X1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Note that since we have not specified any coordinate range in the arguments of chart(), the range of $(x_1,y_1)$ is $\\mathbb{R}^2$.

\n", "

Similarly, let $U_2$ be the set of lines through the origin of $\\mathbb{R}^3$ that are not contained in the plane $x=0$. Any line in $U_2$ is uniquely determined by its intersection $(1,y,z)$ with the plane $x=1$, leading to coordinates $(x_2,y_2)=(y,z)$ on $U_2$:

" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Chart (U_2, (x2, y2))" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "U2 = RP2.open_subset('U_2')\n", "X2. = U2.chart() ; X2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Finally, let $U_3$ be the set of lines through the origin of $\\mathbb{R}^3$ that are not contained in the plane $y=0$. Any line in $U_3$ is uniquely determined by its intersection $(x,1,z)$ with the plane $y=1$, leading to coordinates $(x_3,y_3)=(z,x)$ on $U_3$:

" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Chart (U_3, (x3, y3))" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "U3 = RP2.open_subset('U_3')\n", "X3. = U3.chart() ; X3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

We declare that the union of the three (overlapping) open domains $U_1$, $U_2$ and $U_3$ is $\\mathbb{RP}^2$:

" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "2-dimensional differentiable manifold RP^2" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "RP2.declare_union(U1.union(U2), U3)\n", "U1.union(U2).union(U3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

At this stage, three open covers of $\\mathbb{RP}^2$ have been constructed:

" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[[2-dimensional differentiable manifold RP^2],\n", " [Open subset U_1_union_U_2 of the 2-dimensional differentiable manifold RP^2,\n", " Open subset U_3 of the 2-dimensional differentiable manifold RP^2],\n", " [Open subset U_1 of the 2-dimensional differentiable manifold RP^2,\n", " Open subset U_2 of the 2-dimensional differentiable manifold RP^2,\n", " Open subset U_3 of the 2-dimensional differentiable manifold RP^2]]" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "RP2.open_covers()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Finally, to fully specify the manifold $\\mathbb{RP}^2$, we give the transition maps between the various charts; the transition map between the charts X1=$(U_1,(x_1,y_1))$ and X2=$(U_2,(x_2,y_2))$ is defined on the set $U_{12} := U_1 \\cap U_2$ of lines through the origin of $\\mathbb{R}^3$ that are neither contained in the plane $x=0$ ($x_1=0$ in $U_1$) nor contained in the plane $z=0$ ($y_2=0$ in $U_2$):

" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "x2 = y1/x1\n", "y2 = 1/x1" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X1_to_X2 = X1.transition_map(X2, (y1/x1, 1/x1), intersection_name='U_{12}',\n", " restrictions1= x1!=0, restrictions2= y2!=0)\n", "X1_to_X2.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The inverse of this transition map is easily computed by Sage:

" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "x1 = 1/y2\n", "y1 = x2/y2" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X2_to_X1 = X1_to_X2.inverse()\n", "X2_to_X1.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The transition map between the charts X1=$(U_1,(x_1,y_1))$ and X3=$(U_3,(x_3,y_3))$ is defined on the set $U_{13} := U_1 \\cap U_3$ of lines through the origin of $\\mathbb{R}^3$ that are neither contained in the plane $y=0$ ($y_1=0$ in $U_1$) nor contained in the plane $z=0$ ($x_3=0$ in $U_3$):

" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "x3 = 1/y1\n", "y3 = x1/y1" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X1_to_X3 = X1.transition_map(X3, (1/y1, x1/y1), intersection_name='U_{13}',\n", " restrictions1= y1!=0, restrictions2= x3!=0)\n", "X1_to_X3.display()" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "x1 = y3/x3\n", "y1 = 1/x3" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X3_to_X1 = X1_to_X3.inverse()\n", "X3_to_X1.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Finally, the transition map between the charts X2=$(U_2,(x_2,y_2))$ and X3=$(U_3,(x_3,y_3))$ is defined on the set $U_{23} := U_2 \\cap U_3$ of lines through the origin of $\\mathbb{R}^3$ that are neither contained in the plane $y=0$ ($x_2=0$ in $U_2$) nor contained in the plane $x=0$ ($y_3=0$ in $U_3$):

" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "x3 = y2/x2\n", "y3 = 1/x2" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X2_to_X3 = X2.transition_map(X3, (y2/x2, 1/x2), intersection_name='U_{23}',\n", " restrictions1= x2!=0, restrictions2= y3!=0)\n", "X2_to_X3.display()" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "x2 = 1/y3\n", "y2 = x3/y3" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X3_to_X2 = X2_to_X3.inverse()\n", "X3_to_X2.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

At this stage, the manifold $\\mathbb{RP}^2$ is fully constructed. It has been provided with the following atlas:

" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "[Chart (U_1, (x1, y1)),\n", " Chart (U_2, (x2, y2)),\n", " Chart (U_3, (x3, y3)),\n", " Chart (U_{12}, (x1, y1)),\n", " Chart (U_{12}, (x2, y2)),\n", " Chart (U_{13}, (x1, y1)),\n", " Chart (U_{13}, (x3, y3)),\n", " Chart (U_{23}, (x2, y2)),\n", " Chart (U_{23}, (x3, y3))]" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "RP2.atlas()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Note that, in addition to the three chart we have defined, the atlas comprises subcharts on the intersection domains $U_{12}$, $U_{13}$ and $U_{23}$. These charts can be obtained by the method restrict():

" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Chart (U_{12}, (x1, y1))" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "U12 = U1.intersection(U2)\n", "U13 = U1.intersection(U3)\n", "U23 = U2.intersection(U3)\n", "X1.restrict(U12)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "True" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X1.restrict(U12) is RP2.atlas()[3]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Non-orientability of $\\mathbb{RP}^2$

\n", "

It is well known that $\\mathbb{RP}^2$ is not an orientable manifold. To illustrate this, let us make an attempt to construct a global non-vanishing 2-form $\\epsilon$ on $\\mathbb{RP}^2$. If we succeed, this would provide a volume form and $\\mathbb{RP}^2$ would be orientable. We start by declaring $\\epsilon$ as a 2-form on $\\mathbb{RP}^2$:

" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2-form eps on the 2-dimensional differentiable manifold RP^2\n" ] } ], "source": [ "eps = RP2.diff_form(2, name='eps', latex_name=r'\\epsilon')\n", "print(eps)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

We set the value of $\\epsilon$ on domain $U_1$ to be $\\mathrm{d}x_1 \\wedge \\mathrm{d}y_1$ by demanding that the component $\\epsilon_{01}$ of $\\epsilon$ with respect to coordinates $(x_1,y_1)$  is one, as follows:

" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Coordinate frame (U_1, (d/dx1,d/dy1))" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "e1 = X1.frame() ; e1" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "eps = dx1/\\dy1" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "eps[e1,0,1] = 1\n", "eps.display(e1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

If we ask for the expression of $\\epsilon$ in terms of the coframe $(\\mathrm{d}x_2, \\mathrm{d}y_2)$ associated with the chart X2 on $U_{12} = U_1\\cap U_2$, we get

" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "eps = y2^(-3) dx2/\\dy2" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "eps.display(X2.frame().restrict(U12), chart=X2.restrict(U12))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Now, the complement of $U_{12}$ in $U_2$ is defined by $y_2=0$. The above expression shows that it is not possible to extend smoothly $\\epsilon$ to the whole domain $U_2$. We conclude that starting from $\\mathrm{d}x_1\\wedge\\mathrm{d}y_1$ on $U_1$, it is not possible to get a regular non-vanishing 2-form on $\\mathbb{RP}^2$. This of course follows from the fact that $\\mathbb{RP}^2$ is not orientable.

\n", "\n", "

Steiner map (Roman surface)

\n", "

Let us first define $\\mathbb{R}^3$ as a 3-dimensional manifold, with a single-chart atlas (Cartesian coordinates Y):

" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "R3 = Manifold(3, 'R^3', r'\\mathbb{R}^3')\n", "Y. = R3.chart()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The Steiner map is a map $\\mathbb{RP}^2 \\rightarrow \\mathbb{R}^3$ defined as follows:

" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Phi: RP^2 --> R^3\n", "on U_1: (x1, y1) |--> (x, y, z) = (y1/(x1^2 + y1^2 + 1), x1/(x1^2 + y1^2 + 1), x1*y1/(x1^2 + y1^2 + 1))\n", "on U_2: (x2, y2) |--> (x, y, z) = (x2*y2/(x2^2 + y2^2 + 1), y2/(x2^2 + y2^2 + 1), x2/(x2^2 + y2^2 + 1))\n", "on U_3: (x3, y3) |--> (x, y, z) = (x3/(x3^2 + y3^2 + 1), x3*y3/(x3^2 + y3^2 + 1), y3/(x3^2 + y3^2 + 1))" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Phi = RP2.diff_map(R3, {(X1,Y): [y1/(1+x1^2+y1^2), x1/(1+x1^2+y1^2), x1*y1/(1+x1^2+y1^2)],\n", " (X2,Y): [x2*y2/(1+x2^2+y2^2), y2/(1+x2^2+y2^2), x2/(1+x2^2+y2^2)],\n", " (X3,Y): [x3/(1+x3^2+y3^2), x3*y3/(1+x3^2+y3^2), y3/(1+x3^2+y3^2)]},\n", " name='Phi', latex_name=r'\\Phi')\n", "Phi.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

$\\Phi$ is a topological immersion of $\\mathbb{RP}^2$ into $\\mathbb{R}^3$, but it is not a smooth immersion (contrary to the Apéry map below): its differential is not injective at $(x_1,y_1)=(0,1)$ and $(x_1,y_1)=(1,0)$. The image of $\\Phi$ is a self-intersecting surface of $\\mathbb{R}^3$, called the Roman surface:

" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "Graphics3d Object" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "g1 = parametric_plot3d(Phi.expr(X1,Y), (x1,-10,10), (y1,-10,10), plot_points=[100,100])\n", "g2 = parametric_plot3d(Phi.expr(X2,Y), (x2,-10,10), (y2,-10,10), plot_points=[100,100])\n", "g3 = parametric_plot3d(Phi.expr(X3,Y), (x3,-10,10), (y3,-10,10), plot_points=[100,100])\n", "show(g1+g2+g3, viewer=viewer3D, online=True)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "Graphics3d Object" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "gX1 = X1.plot(Y, mapping=Phi, max_range=16, number_values=24, plot_points=100, \n", " label_axes=False)\n", "gX2 = X2.plot(Y, mapping=Phi, max_range=16, number_values=24, plot_points=100, \n", " label_axes=False, color='green')\n", "gX3 = X3.plot(Y, mapping=Phi, max_range=16, number_values=24, plot_points=100, \n", " label_axes=False, color='blue')\n", "show(gX1, viewer=viewer3D, online=True)" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "Graphics3d Object" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show(gX2, viewer=viewer3D, online=True)" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "Graphics3d Object" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show(gX3, viewer=viewer3D, online=True)" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "Graphics3d Object" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show(gX1+gX2+gX3, viewer=viewer3D, online=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Apéry map (Boy surface)

\n", "

The Apéry map [Apéry, Adv. Math. 61, 185 (1986)] is a smooth immersion $\\Psi: \\mathbb{RP}^2 \\rightarrow \\mathbb{R}^3$. In terms of the charts X1, X2, X3 introduced above, it is defined as follows:

" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "1/2*(y^2 - z^2)*x*y + 1/2*(x^2 - z^2)*x*z + (y^2 - z^2)*y*z + 1/2*(2*x^2 - y^2 - z^2)*(x^2 + y^2 + z^2)" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fx = ((2*x^2-y^2-z^2)*(x^2+y^2+z^2)+2*y*z*(y^2-z^2)+z*x*(x^2-z^2)+x*y*(y^2-z^2))/2 ; fx" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "-1/2*sqrt(3)*((x^2 - y^2)*x*y + (x^2 - z^2)*x*z - (x^2 + y^2 + z^2)*(y^2 - z^2))" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fy = sqrt(3)/2*((y^2-z^2)*(x^2+y^2+z^2)+z*x*(z^2-x^2)+x*y*(y^2-x^2)) ; fy" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "1/4*((x + y + z)^3 + 4*(x - y)*(x - z)*(y - z))*(x + y + z)" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fz = (x+y+z)*((x+y+z)^3/4+(y-x)*(z-y)*(x-z)) ; fz" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "a = sqrt(1+x1^2+y1^2)\n", "fx1 = fx.subs(x=x1/a, y=y1/a, z=1/a).simplify_full()\n", "fy1 = fy.subs(x=x1/a, y=y1/a, z=1/a).simplify_full()\n", "fz1 = fz.subs(x=x1/a, y=y1/a, z=1/a).simplify_full()" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [], "source": [ "a = sqrt(1+x2^2+y2^2)\n", "fx2 = fx.subs(x=1/a, y=x2/a, z=y2/a).simplify_full()\n", "fy2 = fy.subs(x=1/a, y=x2/a, z=y2/a).simplify_full()\n", "fz2 = fz.subs(x=1/a, y=x2/a, z=y2/a).simplify_full()" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [], "source": [ "a = sqrt(1+x3^2+y3^2)\n", "fx3 = fx.subs(x=y3/a, y=1/a, z=x3/a).simplify_full()\n", "fy3 = fy.subs(x=y3/a, y=1/a, z=x3/a).simplify_full()\n", "fz3 = fz.subs(x=y3/a, y=1/a, z=x3/a).simplify_full()" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "Psi: RP^2 --> R^3\n", "on U_1: (x1, y1) |--> (x, y, z) = (1/2*(2*x1^4 + (x1 + 2)*y1^3 - y1^4 + x1^3 + (x1^2 - 2)*y1^2 + x1^2 - (x1 + 2)*y1 - x1 - 1)/(x1^4 + y1^4 + 2*(x1^2 + 1)*y1^2 + 2*x1^2 + 1), -1/2*(sqrt(3)*x1^3*y1 - sqrt(3)*x1^2*y1^2 - sqrt(3)*x1*y1^3 - sqrt(3)*y1^4 + sqrt(3)*x1^3 + sqrt(3)*x1^2 - sqrt(3)*x1 + sqrt(3))/(x1^4 + y1^4 + 2*(x1^2 + 1)*y1^2 + 2*x1^2 + 1), 1/4*(x1^4 + y1^4 + 6*(x1^2 + 2*x1 + 1)*y1^2 + 8*y1^3 + 6*x1^2 + 4*(2*x1^3 + 3*x1^2 + 3*x1)*y1 + 8*x1 + 1)/(x1^4 + y1^4 + 2*(x1^2 + 1)*y1^2 + 2*x1^2 + 1))\n", "on U_2: (x2, y2) |--> (x, y, z) = (-1/2*(x2^4 + (2*x2 + 1)*y2^3 + y2^4 - x2^3 + (2*x2^2 + x2 - 1)*y2^2 - x2^2 - (2*x2^3 + 1)*y2 - 2)/(x2^4 + y2^4 + 2*(x2^2 + 1)*y2^2 + 2*x2^2 + 1), 1/2*(sqrt(3)*x2^4 - sqrt(3)*y2^4 + sqrt(3)*x2^3 + sqrt(3)*y2^3 + sqrt(3)*x2^2 - sqrt(3)*y2^2 - sqrt(3)*x2 - sqrt(3)*y2)/(x2^4 + y2^4 + 2*(x2^2 + 1)*y2^2 + 2*x2^2 + 1), 1/4*(x2^4 + y2^4 + 6*(x2^2 + 2*x2 + 1)*y2^2 + 8*y2^3 + 6*x2^2 + 4*(2*x2^3 + 3*x2^2 + 3*x2)*y2 + 8*x2 + 1)/(x2^4 + y2^4 + 2*(x2^2 + 1)*y2^2 + 2*x2^2 + 1))\n", "on U_3: (x3, y3) |--> (x, y, z) = (-1/2*(x3^4 - x3*y3^3 - 2*y3^4 + 2*x3^3 - (x3^2 + 1)*y3^2 + 2*x3^2 + (x3^3 + x3^2 - 1)*y3 - 2*x3 + 1)/(x3^4 + y3^4 + 2*(x3^2 + 1)*y3^2 + 2*x3^2 + 1), -1/2*(sqrt(3)*x3^4 + (sqrt(3)*x3 + sqrt(3))*y3^3 + (sqrt(3)*x3^2 - sqrt(3))*y3^2 - (sqrt(3)*x3^3 + sqrt(3))*y3 - sqrt(3))/(x3^4 + y3^4 + 2*(x3^2 + 1)*y3^2 + 2*x3^2 + 1), 1/4*(x3^4 + y3^4 + 6*(x3^2 + 2*x3 + 1)*y3^2 + 8*y3^3 + 6*x3^2 + 4*(2*x3^3 + 3*x3^2 + 3*x3)*y3 + 8*x3 + 1)/(x3^4 + y3^4 + 2*(x3^2 + 1)*y3^2 + 2*x3^2 + 1))" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Psi = RP2.diff_map(R3, {(X1,Y): [fx1, fy1, fz1], (X2,Y): [fx2, fy2, fz2],\n", " (X3,Y): [fx3, fy3, fz3]}, name='Psi', latex_name=r'\\Psi')\n", "Psi.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

The image of $\\Psi$ is a self-intersecting surface of $\\mathbb{R}^3$, called the Boy surface, after Werner Boy (1879-1914):

" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "Graphics3d Object" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "g1 = parametric_plot3d(Psi.expr(X1,Y), (x1,-10,10), (y1,-10,10), plot_points=[100,100])\n", "g2 = parametric_plot3d(Psi.expr(X2,Y), (x2,-10,10), (y2,-10,10), plot_points=[100,100])\n", "g3 = parametric_plot3d(Psi.expr(X3,Y), (x3,-10,10), (y3,-10,10), plot_points=[100,100])\n", "show(g1+g2+g3, viewer=viewer3D, online=True)" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [], "source": [ "gX1 = X1.plot(Y, mapping=Psi, number_values=40, plot_points=100, label_axes=False)\n", "gX2 = X2.plot(Y, mapping=Psi, number_values=40, plot_points=100, label_axes=False,\n", " color='green')\n", "gX3 = X3.plot(Y, mapping=Psi, number_values=40, plot_points=100, label_axes=False,\n", " color='blue')" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "Graphics3d Object" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show(gX1, viewer=viewer3D, online=True)" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "Graphics3d Object" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show(gX2, viewer=viewer3D, online=True)" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "Graphics3d Object" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show(gX3, viewer=viewer3D, online=True)" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "Graphics3d Object" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show(gX1+gX2+gX3, viewer=viewer3D, online=True)" ] } ], "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 }