This Jupyter 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.

A version of SageMath at least equal to 7.5 is required to run this notebook:

In [1]:

```
version()
```

Out[1]:

First we set up the notebook to use LaTeX for rendering outputs:

In [2]:

```
%display latex
```

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

In [3]:

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

Out[3]:

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 [4]:

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

Out[4]:

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 [5]:

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

Out[5]:

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 [6]:

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

Out[6]:

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 [7]:

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

Out[7]:

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

In [8]:

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

Out[8]:

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

In [9]:

```
RP2.open_covers()
```

Out[9]:

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 [10]:

```
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[10]:

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

In [11]:

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

Out[11]:

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 [12]:

```
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[12]:

In [13]:

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

Out[13]:

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 [14]:

```
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[14]:

In [15]:

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

Out[15]:

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

In [16]:

```
RP2.atlas()
```

Out[16]:

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 [17]:

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

Out[17]:

In [18]:

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

Out[18]:

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 [19]:

```
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 [20]:

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

Out[20]:

In [21]:

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

Out[21]:

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 [22]:

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

Out[22]:

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 [23]:

```
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 [24]:

```
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[24]:

$\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 [25]:

```
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])
g1+g2+g3
```

Out[25]: