# Hyperbolic plane $\mathbb{H}^2$¶

This worksheet illustrates some features of SageManifolds (v1.0, as included in SageMath 7.5) on computations regarding the hyperbolic plane.

Click here to download the worksheet 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]:
'SageMath version 7.5, Release Date: 2017-01-11'

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

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 declare $\mathbb{H}^2$ as a 2-dimensional differentiable manifold:

In [4]:
H2 = Manifold(2, 'H2', latex_name=r'\mathbb{H}^2', start_index=1)
print(H2)
H2

2-dimensional differentiable manifold H2

Out[4]:

We shall introduce charts on $\mathbb{H}^2$ that are related to various models of the hyperbolic plane as submanifolds of $\mathbb{R}^3$. Therefore, we start by declaring $\mathbb{R}^3$ as a 3-dimensional manifold equiped with a global chart: the chart of Cartesian coordinates $(X,Y,Z)$:

In [5]:
R3 = Manifold(3, 'R3', latex_name=r'\mathbb{R}^3', start_index=1)
X3.<X,Y,Z> = R3.chart()
X3

Out[5]:

## Hyperboloid model¶

The first chart we introduce is related to the hyperboloid model of $\mathbb{H}^2$, namely to the representation of $\mathbb{H}^2$ as the upper sheet ($Z>0$) of the hyperboloid of two sheets defined in $\mathbb{R}^3$ by the equation $X^2 + Y^2 - Z^2 = -1$:

In [6]:
X_hyp.<X,Y> = H2.chart()
X_hyp

Out[6]:

The corresponding embedding of $\mathbb{H}^2$ in $\mathbb{R}^3$ is

In [7]:
Phi1 = H2.diff_map(R3, [X, Y, sqrt(1+X^2+Y^2)], name='Phi_1', latex_name=r'\Phi_1')
Phi1.display()

Out[7]:

By plotting the chart $\left(\mathbb{H}^2,(X,Y)\right)$ in terms of the Cartesian coordinates of $\mathbb{R}^3$, we get a graphical view of $\Phi_1(\mathbb{H}^2)$:

In [8]:
show(X_hyp.plot(X3, mapping=Phi1, number_values=15, color='blue'), aspect_ratio=1,
viewer=viewer3D, figsize=7)


A second chart is obtained from the polar coordinates $(r,\varphi)$ associated with $(X,Y)$. Contrary to $(X,Y)$, the polar chart is not defined on the whole $\mathbb{H}^2$, but on the complement $U$ of the segment $\{Y=0, x\geq 0\}$:

In [9]:
U = H2.open_subset('U', coord_def={X_hyp: (Y!=0, X<0)})
print(U)

Open subset U of the 2-dimensional differentiable manifold H2


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.

In [10]:
X_pol.<r,ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):\varphi')
X_pol

Out[10]:
In [11]:
X_pol.coord_range()

Out[11]:

We specify the transition map between the charts $\left(U,(r,\varphi)\right)$ and $\left(\mathbb{H}^2,(X,Y)\right)$ as $X=r\cos\varphi$, $Y=r\sin\varphi$:

In [12]:
pol_to_hyp = X_pol.transition_map(X_hyp, [r*cos(ph), r*sin(ph)])
pol_to_hyp

Out[12]:
In [13]:
pol_to_hyp.display()

Out[13]:
In [14]:
pol_to_hyp.set_inverse(sqrt(X^2+Y^2), atan2(Y, X))

In [15]:
pol_to_hyp.inverse().display()

Out[15]:

The restriction of the embedding $\Phi_1$ to $U$ has then two coordinate expressions:

In [16]:
Phi1.restrict(U).display()

Out[16]:
In [17]:
graph_hyp = X_pol.plot(X3, mapping=Phi1.restrict(U), number_values=15, ranges={r: (0,3)},
color='blue')
show(graph_hyp, aspect_ratio=1, viewer=viewer3D, figsize=7)

In [18]:
Phi1._coord_expression

Out[18]:

## Metric and curvature¶

The metric on $\mathbb{H}^2$ is that induced by the Minkowksy metric on $\mathbb{R}^3$: $$\eta = \mathrm{d}X\otimes\mathrm{d}X + \mathrm{d}Y\otimes\mathrm{d}Y • \mathrm{d}Z\otimes\mathrm{d}Z$$
In [19]:
eta = R3.lorentzian_metric('eta', latex_name=r'\eta')
eta[1,1] = 1 ; eta[2,2] = 1 ; eta[3,3] = -1
eta.display()

Out[19]:
In [20]:
g = H2.metric('g')
g.set( Phi1.pullback(eta) )
g.display()

Out[20]:

The expression of the metric tensor in terms of the polar coordinates is

In [21]:
g.display(X_pol.frame(), X_pol)

Out[21]:

The Riemann curvature tensor associated with $g$ is

In [22]:
Riem = g.riemann()
print(Riem)

Tensor field Riem(g) of type (1,3) on the 2-dimensional differentiable manifold H2

In [23]:
Riem.display(X_pol.frame(), X_pol)

Out[23]:

The Ricci tensor and the Ricci scalar:

In [24]:
Ric = g.ricci()
print(Ric)

Field of symmetric bilinear forms Ric(g) on the 2-dimensional differentiable manifold H2

In [25]:
Ric.display(X_pol.frame(), X_pol)

Out[25]:
In [26]:
Rscal = g.ricci_scalar()
print(Rscal)

Scalar field r(g) on the 2-dimensional differentiable manifold H2

In [27]:
Rscal.display()

Out[27]:

Hence we recover the fact that $(\mathbb{H}^2,g)$ is a space of constant negative curvature.

In dimension 2, the Riemann curvature tensor is entirely determined by the Ricci scalar $R$ according to

$$R^i_{\ \, jlk} = \frac{R}{2} \left( \delta^i_{\ \, k} g_{jl} - \delta^i_{\ \, l} g_{jk} \right)$$

Let us check this formula here, under the form $R^i_{\ \, jlk} = -R g_{j[k} \delta^i_{\ \, l]}$:

In [28]:
delta = H2.tangent_identity_field()
Riem == - Rscal*(g*delta).antisymmetrize(2,3)  # 2,3 = last positions of the type-(1,3) tensor g*delta

Out[28]:

Similarly the relation $\mathrm{Ric} = (R/2)\; g$ must hold:

In [29]:
Ric == (Rscal/2)*g

Out[29]:

## Poincaré disk model¶

The Poincaré disk model of $\mathbb{H}^2$ is obtained by stereographic projection from the point $S=(0,0,-1)$ of the hyperboloid model to the plane $Z=0$. The radial coordinate $R$ of the image of a point of polar coordinate $(r,\varphi)$ is $$R = \frac{r}{1+\sqrt{1+r^2}}.$$ Hence we define the Poincaré disk chart on $\mathbb{H}^2$ by

In [30]:
X_Pdisk.<R,ph> = U.chart(r'R:(0,1) ph:(0,2*pi):\varphi')
X_Pdisk

Out[30]:
In [31]:
X_Pdisk.coord_range()

Out[31]:

and relate it to the hyperboloid polar chart by

In [32]:
pol_to_Pdisk = X_pol.transition_map(X_Pdisk, [r/(1+sqrt(1+r^2)), ph])
pol_to_Pdisk

Out[32]:
In [33]:
pol_to_Pdisk.display()

Out[33]:
In [34]:
pol_to_Pdisk.set_inverse(2*R/(1-R^2), ph)
pol_to_Pdisk.inverse().display()

Out[34]:

A view of the Poincaré disk chart via the embedding $\Phi_1$:

In [35]:
show(X_Pdisk.plot(X3, mapping=Phi1.restrict(U), ranges={R: (0,0.9)}, color='blue',
number_values=15), aspect_ratio=1, viewer=viewer3D, figsize=7)


The expression of the metric tensor in terms of coordinates $(R,\varphi)$:

In [36]:
g.display(X_Pdisk.frame(), X_Pdisk)

Out[36]:

We may factorize each metric component:

In [37]:
for i in [1,2]:
g[X_Pdisk.frame(), i, i, X_Pdisk].factor()
g.display(X_Pdisk.frame(), X_Pdisk)

Out[37]:

### Cartesian coordinates on the Poincaré disk¶

Let us introduce Cartesian coordinates $(u,v)$ on the Poincaré disk; since the latter has a unit radius, this amounts to define the following chart on $\mathbb{H}^2$:

In [38]:
X_Pdisk_cart.<u,v> = H2.chart('u:(-1,1) v:(-1,1)')
X_Pdisk_cart

Out[38]:

On $U$, the Cartesian coordinates $(u,v)$ are related to the polar coordinates $(R,\varphi)$ by the standard formulas:

In [39]:
Pdisk_to_Pdisk_cart = X_Pdisk.transition_map(X_Pdisk_cart, [R*cos(ph), R*sin(ph)])
Pdisk_to_Pdisk_cart

Out[39]:
In [40]:
Pdisk_to_Pdisk_cart.display()

Out[40]:
In [41]:
Pdisk_to_Pdisk_cart.set_inverse(sqrt(u^2+v^2), atan2(v, u))
Pdisk_to_Pdisk_cart.inverse().display()

Out[41]:

The embedding of $\mathbb{H}^2$ in $\mathbb{R}^3$ associated with the Poincaré disk model is naturally defined as

In [42]:
Phi2 = H2.diff_map(R3, {(X_Pdisk_cart, X3): [u, v, 0]},
name='Phi_2', latex_name=r'\Phi_2')
Phi2.display()

Out[42]:

Let us use it to draw the Poincaré disk in $\mathbb{R}^3$:

In [43]:
graph_disk_uv = X_Pdisk_cart.plot(X3, mapping=Phi2, number_values=15)
show(graph_disk_uv, viewer=viewer3D, figsize=7)


On $U$, the change of coordinates $(r,\varphi) \rightarrow (u,v)$ is obtained by combining the changes $(r,\varphi) \rightarrow (R,\varphi)$ and $(R,\varphi) \rightarrow (u,v)$:

In [44]:
pol_to_Pdisk_cart = Pdisk_to_Pdisk_cart * pol_to_Pdisk
pol_to_Pdisk_cart

Out[44]:
In [45]:
pol_to_Pdisk_cart.display()

Out[45]:

Still on $U$, the change of coordinates $(X,Y) \rightarrow (u,v)$ is obtained by combining the changes $(X,Y) \rightarrow (r,\varphi)$ with $(r,\varphi) \rightarrow (u,v)$:

In [46]:
hyp_to_Pdisk_cart_U = pol_to_Pdisk_cart * pol_to_hyp.inverse()
hyp_to_Pdisk_cart_U

Out[46]:
In [47]:
hyp_to_Pdisk_cart_U.display()

Out[47]:

We use the above expression to extend the change of coordinates $(X,Y) \rightarrow (u,v)$ from $U$ to the whole manifold $\mathbb{H}^2$:

In [48]:
hyp_to_Pdisk_cart = X_hyp.transition_map(X_Pdisk_cart, hyp_to_Pdisk_cart_U(X,Y))
hyp_to_Pdisk_cart

Out[48]:
In [49]:
hyp_to_Pdisk_cart.display()

Out[49]:
In [50]:
hyp_to_Pdisk_cart.set_inverse(2*u/(1-u^2-v^2), 2*v/(1-u^2-v^2))
hyp_to_Pdisk_cart.inverse().display()

Out[50]:
In [51]:
graph_Pdisk = X_pol.plot(X3, mapping=Phi2.restrict(U), ranges={r: (0, 20)}, number_values=15,
label_axes=False)
show(graph_hyp + graph_Pdisk, aspect_ratio=1, viewer=viewer3D, figsize=7)

In [52]:
X_pol.plot(X_Pdisk_cart, ranges={r: (0, 20)}, number_values=15)

Out[52]:

### Metric tensor in Poincaré disk coordinates $(u,v)$¶

From now on, we are using the Poincaré disk chart $(\mathbb{H}^2,(u,v))$ as the default one on $\mathbb{H}^2$:

In [53]:
H2.set_default_chart(X_Pdisk_cart)
H2.set_default_frame(X_Pdisk_cart.frame())

In [54]:
g.display(X_hyp.frame())

Out[54]:
In [55]:
g.display()

Out[55]:
In [56]:
g[1,1].factor() ; g[2,2].factor()
g.display()

Out[56]:

## Hemispherical model¶

The hemispherical model of $\mathbb{H}^2$ is obtained by the inverse stereographic projection from the point $S = (0,0,-1)$ of the Poincaré disk to the unit sphere $X^2+Y^2+Z^2=1$. This induces a spherical coordinate chart on $U$:

In [57]:
X_spher.<th,ph> = U.chart(r'th:(0,pi/2):\theta ph:(0,2*pi):\varphi')
X_spher

Out[57]:

From the stereographic projection from $S$, we obtain that $$\sin\theta = \frac{2R}{1+R^2}$$ Hence the transition map:

In [58]:
Pdisk_to_spher = X_Pdisk.transition_map(X_spher, [arcsin(2*R/(1+R^2)), ph])
Pdisk_to_spher

Out[58]:
In [59]:
Pdisk_to_spher.display()

Out[59]:
In [60]:
Pdisk_to_spher.set_inverse(sin(th)/(1+cos(th)), ph)
Pdisk_to_spher.inverse().display()

Out[60]:

In the spherical coordinates $(\theta,\varphi)$, the metric takes the following form:

In [61]:
g.display(X_spher.frame(), X_spher)

Out[61]:

The embedding of $\mathbb{H}^2$ in $\mathbb{R}^3$ associated with the hemispherical model is naturally:

In [62]:
Phi3 = H2.diff_map(R3, {(X_spher, X3): [sin(th)*cos(ph), sin(th)*sin(ph), cos(th)]},
name='Phi_3', latex_name=r'\Phi_3')
Phi3.display()

Out[62]:
In [63]:
graph_spher = X_pol.plot(X3, mapping=Phi3, ranges={r: (0, 20)}, number_values=15, color='orange',
label_axes=False)
show(graph_hyp + graph_Pdisk + graph_spher, aspect_ratio=1, viewer=viewer3D, figsize=7)