This notebook demonstrates some capabilities of SageMath about differentiable manifolds on the example of real projective plane. The corresponding tools have been developed within the SageManifolds project (version 1.3, as included in SageMath 8.3).

Click here to download the notebook file (ipynb format). To run it, you must start SageMath with the Jupyter notebook, via the command `sage -n jupyter`

*NB:* a version of SageMath at least equal to 7.5 is required to run this worksheet:

In [1]:

```
version()
```

Out[1]:

First we set up the notebook to display mathematical objects using LaTeX rendering:

In [2]:

```
%display latex
```

We also define a viewer for 3D plots (use `'threejs'`

or `'jmol'`

for interactive 3D graphics):

In [3]:

```
viewer3D = 'threejs' # must be 'threejs', 'jmol', 'tachyon' or None (default)
```

We start by declaring the real projective plane as a 2-dimensional differentiable manifold:

In [4]:

```
RP2 = Manifold(2, 'RP^2', r'\mathbb{RP}^2') ; RP2
```

Out[4]:

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:

In [5]:

```
U1 = RP2.open_subset('U_1') ; U1
```

Out[5]:

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)$:

In [6]:

```
X1.<x1,y1> = U1.chart() ; X1
```

Out[6]:

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$.

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$:

In [7]:

```
U2 = RP2.open_subset('U_2')
X2.<x2,y2> = U2.chart() ; X2
```

Out[7]:

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$:

In [8]:

```
U3 = RP2.open_subset('U_3')
X3.<x3,y3> = U3.chart() ; X3
```

Out[8]:

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

In [9]:

```
RP2.declare_union(U1.union(U2), U3)
U1.union(U2).union(U3)
```

Out[9]:

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

In [10]:

```
RP2.open_covers()
```

Out[10]:

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$):

In [11]:

```
X1_to_X2 = X1.transition_map(X2, (y1/x1, 1/x1), intersection_name='U_{12}',
restrictions1= x1!=0, restrictions2= y2!=0)
X1_to_X2.display()
```

Out[11]:

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

In [12]:

```
X2_to_X1 = X1_to_X2.inverse()
X2_to_X1.display()
```

Out[12]:

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$):

In [13]:

```
X1_to_X3 = X1.transition_map(X3, (1/y1, x1/y1), intersection_name='U_{13}',
restrictions1= y1!=0, restrictions2= x3!=0)
X1_to_X3.display()
```

Out[13]:

In [14]:

```
X3_to_X1 = X1_to_X3.inverse()
X3_to_X1.display()
```

Out[14]:

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$):

In [15]:

```
X2_to_X3 = X2.transition_map(X3, (y2/x2, 1/x2), intersection_name='U_{23}',
restrictions1= x2!=0, restrictions2= y3!=0)
X2_to_X3.display()
```

Out[15]:

In [16]:

```
X3_to_X2 = X2_to_X3.inverse()
X3_to_X2.display()
```

Out[16]:

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

In [17]:

```
RP2.atlas()
```

Out[17]:

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():

In [18]:

```
U12 = U1.intersection(U2)
U13 = U1.intersection(U3)
U23 = U2.intersection(U3)
X1.restrict(U12)
```

Out[18]:

In [19]:

```
X1.restrict(U12) is RP2.atlas()[3]
```

Out[19]:

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$:

In [20]:

```
eps = RP2.diff_form(2, name='eps', latex_name=r'\epsilon')
print(eps)
```

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:

In [21]:

```
e1 = X1.frame() ; e1
```

Out[21]:

In [22]:

```
eps[e1,0,1] = 1
eps.display(e1)
```

Out[22]:

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

In [23]:

```
eps.display(X2.frame().restrict(U12), chart=X2.restrict(U12))
```

Out[23]:

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.

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

In [24]:

```
R3 = Manifold(3, 'R^3', r'\mathbb{R}^3')
Y.<x,y,z> = R3.chart()
```

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

In [25]:

```
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)],
(X2,Y): [x2*y2/(1+x2^2+y2^2), y2/(1+x2^2+y2^2), x2/(1+x2^2+y2^2)],
(X3,Y): [x3/(1+x3^2+y3^2), x3*y3/(1+x3^2+y3^2), y3/(1+x3^2+y3^2)]},
name='Phi', latex_name=r'\Phi')
Phi.display()
```

Out[25]:

$\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**:

In [26]:

```
g1 = parametric_plot3d(Phi.expr(X1,Y), (x1,-10,10), (y1,-10,10), plot_points=[100,100])
g2 = parametric_plot3d(Phi.expr(X2,Y), (x2,-10,10), (y2,-10,10), plot_points=[100,100])
g3 = parametric_plot3d(Phi.expr(X3,Y), (x3,-10,10), (y3,-10,10), plot_points=[100,100])
show(g1+g2+g3, viewer=viewer3D, online=True)
```