Hyperbolic plane $\mathbb{H}^2$

This worksheet illustrates some features of SageManifolds (v0.8) on computations regarding the hyperbolic plane.

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

In [1]:
%display latex

We also define a viewer for 3D plots:

In [2]:
viewer3D = 'tachyon' # must be 'jmol', 'tachyon' or None (default)

We declare $\mathbb{H}^2$ as a 2-dimensional differentiable manifold:

In [3]:
H2 = Manifold(2, 'H2', latex_name=r'\mathbb{H}^2', start_index=1)
print H2
H2
2-dimensional manifold 'H2'
Out[3]:

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 [4]:
R3 = Manifold(3, 'R3', latex_name=r'\mathbb{R}^3', start_index=1)
X3.<X,Y,Z> = R3.chart()
X3
Out[4]:

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 [5]:
X_hyp.<X,Y> = H2.chart()
X_hyp
Out[5]:

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

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

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 [7]:
show(X_hyp.plot(X3, mapping=Phi1, nb_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 [8]:
U = H2.open_subset('U', coord_def={X_hyp: (Y!=0, X<0)})
print U
open subset 'U' of the 2-dimensional 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 [9]:
X_pol.<r,ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):\varphi')
X_pol
Out[9]:
In [10]:
X_pol.coord_range()
Out[10]:

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 [11]:
pol_to_hyp = X_pol.transition_map(X_hyp, [r*cos(ph), r*sin(ph)])
pol_to_hyp
Out[11]:
In [12]:
pol_to_hyp.display()
Out[12]:
In [13]:
pol_to_hyp.set_inverse(sqrt(X^2+Y^2), atan2(Y, X)) 
Check of the inverse coordinate transformation:
   r == r
   ph == arctan2(r*sin(ph), r*cos(ph))
   X == X
   Y == Y
In [14]:
pol_to_hyp.inverse().display()
Out[14]:

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

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

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 [18]:
eta = R3.lorentz_metric('eta', latex_name=r'\eta')
eta[1,1] = 1 ; eta[2,2] = 1 ; eta[3,3] = -1
eta.display()
Out[18]:
In [19]:
g = H2.riemann_metric('g')
g.set( Phi1.pullback(eta) )
g.display() 
Out[19]:

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

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

The Riemann curvature tensor associated with $g$ is

In [21]:
Riem = g.riemann()
print Riem
tensor field 'Riem(g)' of type (1,3) on the 2-dimensional manifold 'H2'
In [22]:
Riem.display(X_pol.frame(), X_pol)
Out[22]:

The Ricci tensor and the Ricci scalar:

In [23]:
Ric = g.ricci()
print Ric
field of symmetric bilinear forms 'Ric(g)' on the 2-dimensional manifold 'H2'
In [24]:
Ric.display(X_pol.frame(), X_pol)
Out[24]:
In [25]:
Rscal = g.ricci_scalar()
print Rscal
scalar field 'r(g)' on the 2-dimensional manifold 'H2'
In [26]:
Rscal.display()
Out[26]:

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

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

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

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 [29]:
X_Pdisk.<R,ph> = U.chart(r'R:(0,1) ph:(0,2*pi):\varphi')
X_Pdisk
Out[29]:
In [30]:
X_Pdisk.coord_range()
Out[30]:

and relate it to the hyperboloid polar chart by

In [31]:
pol_to_Pdisk = X_pol.transition_map(X_Pdisk, [r/(1+sqrt(1+r^2)), ph])
pol_to_Pdisk
Out[31]:
In [32]:
pol_to_Pdisk.display()
Out[32]:
In [33]:
pol_to_Pdisk.set_inverse(2*R/(1-R^2), ph)
pol_to_Pdisk.inverse().display()
Check of the inverse coordinate transformation:
   r == r
   ph == ph
   R == R
   ph == ph
Out[33]:

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

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

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

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

We may factorize each metric component:

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

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 [37]:
X_Pdisk_cart.<u,v> = H2.chart('u:(-1,1) v:(-1,1)')
X_Pdisk_cart.add_restrictions(u^2+v^2 < 1)
X_Pdisk_cart
Out[37]:

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

In [38]:
Pdisk_to_Pdisk_cart = X_Pdisk.transition_map(X_Pdisk_cart, [R*cos(ph), R*sin(ph)])
Pdisk_to_Pdisk_cart
Out[38]:
In [39]:
Pdisk_to_Pdisk_cart.display()
Out[39]:
In [40]:
Pdisk_to_Pdisk_cart.set_inverse(sqrt(u^2+v^2), atan2(v, u)) 
Pdisk_to_Pdisk_cart.inverse().display()
Check of the inverse coordinate transformation:
   R == R
   ph == arctan2(R*sin(ph), R*cos(ph))
   u == u
   v == v
Out[40]:

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

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

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

In [42]:
graph_disk_uv = X_Pdisk_cart.plot(X3, mapping=Phi2, nb_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 [43]:
pol_to_Pdisk_cart = Pdisk_to_Pdisk_cart * pol_to_Pdisk
pol_to_Pdisk_cart
Out[43]:
In [44]:
pol_to_Pdisk_cart.display()
Out[44]:

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 [45]:
hyp_to_Pdisk_cart_U = pol_to_Pdisk_cart * pol_to_hyp.inverse()
hyp_to_Pdisk_cart_U
Out[45]:
In [46]:
hyp_to_Pdisk_cart_U.display()
Out[46]:

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 [47]:
hyp_to_Pdisk_cart = X_hyp.transition_map(X_Pdisk_cart, hyp_to_Pdisk_cart_U(X,Y))
hyp_to_Pdisk_cart
Out[47]:
In [48]:
hyp_to_Pdisk_cart.display()
Out[48]:
In [49]:
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()
Check of the inverse coordinate transformation:
   X == X
   Y == Y
   u == -2*u*abs(u^2 + v^2 - 1)/(u^4 + 2*u^2*v^2 + v^4 + (u^2 + v^2 - 1)*abs(u^2 + v^2 - 1) - 1)
   v == -2*v*abs(u^2 + v^2 - 1)/(u^4 + 2*u^2*v^2 + v^4 + (u^2 + v^2 - 1)*abs(u^2 + v^2 - 1) - 1)
Out[49]:
In [50]:
graph_Pdisk = X_pol.plot(X3, mapping=Phi2.restrict(U), ranges={r: (0, 20)}, nb_values=15, 
                         label_axes=False)
show(graph_hyp + graph_Pdisk, aspect_ratio=1, viewer=viewer3D, figsize=7)
In [51]:
X_pol.plot(X_Pdisk_cart, ranges={r: (0, 20)}, nb_values=15)
Out[51]:

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 [52]:
H2.set_default_chart(X_Pdisk_cart)
H2.set_default_frame(X_Pdisk_cart.frame())
In [53]:
g.display(X_hyp.frame())
Out[53]:
In [54]:
g.display()
Out[54]:
In [55]:
g[1,1].factor() ; g[2,2].factor()
g.display()
Out[55]:

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 [56]:
X_spher.<th,ph> = U.chart(r'th:(0,pi/2):\theta ph:(0,2*pi):\varphi')
X_spher
Out[56]:

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

In [57]:
Pdisk_to_spher = X_Pdisk.transition_map(X_spher, [arcsin(2*R/(1+R^2)), ph])
Pdisk_to_spher
Out[57]:
In [58]:
Pdisk_to_spher.display()
Out[58]:
In [59]:
Pdisk_to_spher.set_inverse(sin(th)/(1+cos(th)), ph)
Pdisk_to_spher.inverse().display()
Check of the inverse coordinate transformation:
   R == R
   ph == ph
   th == th
   ph == ph
Out[59]:

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

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

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

In [61]:
Phi3 = H2.diff_mapping(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[61]:
In [62]:
graph_spher = X_pol.plot(X3, mapping=Phi3, ranges={r: (0, 20)}, nb_values=15, color='orange', 
                         label_axes=False)
show(graph_hyp + graph_Pdisk + graph_spher, aspect_ratio=1, viewer=viewer3D, figsize=7)

Poincaré half-plane model

The Poincaré half-plane model of $\mathbb{H}^2$ is obtained by stereographic projection from the point $W=(-1,0,0)$ of the hemispherical model to the plane $X=1$. This induces a new coordinate chart on $\mathbb{H}^2$ by setting $(x,y)=(Y,Z)$ in the plane $X=1$:

In [63]:
X_hplane.<x,y> = H2.chart('x y:(0,+oo)')
X_hplane
Out[63]:

The coordinate transformation $(\theta,\varphi)\rightarrow (x,y)$ is easily deduced from the stereographic projection from the point $W$:

In [64]:
spher_to_hplane = X_spher.transition_map(X_hplane, [2*sin(th)*sin(ph)/(1+sin(th)*cos(ph)),
                                                    2*cos(th)/(1+sin(th)*cos(ph))])
spher_to_hplane
Out[64]:
In [65]:
spher_to_hplane.display()
Out[65]:
In [66]:
Pdisk_to_hplane = spher_to_hplane * Pdisk_to_spher
Pdisk_to_hplane
Out[66]:
In [67]:
Pdisk_to_hplane.display()
Out[67]:
In [68]:
Pdisk_cart_to_hplane_U = Pdisk_to_hplane * Pdisk_to_Pdisk_cart.inverse()
Pdisk_cart_to_hplane_U
Out[68]:
In [69]:
Pdisk_cart_to_hplane_U.display()
Out[69]:

Let us use the above formula to define the transition map $(u,v)\rightarrow (x,y)$ on the whole manifold $\mathbb{H}^2$ (and not only on $U$):

In [70]:
Pdisk_cart_to_hplane = X_Pdisk_cart.transition_map(X_hplane, Pdisk_cart_to_hplane_U(u,v))
Pdisk_cart_to_hplane
Out[70]:
In [71]:
Pdisk_cart_to_hplane.display()
Out[71]:
In [72]:
Pdisk_cart_to_hplane.set_inverse((4-x^2-y^2)/(x^2+(2+y)^2), 4*x/(x^2+(2+y)^2))
Pdisk_cart_to_hplane.inverse().display()
Check of the inverse coordinate transformation:
   u == u
   v == v
   x == x
   y == y
Out[72]:

Since the coordinates $(x,y)$ correspond to $(Y,Z)$ in the plane $X=1$, the embedding of $\mathbb{H}^2$ in $\mathbb{R}^3$ naturally associated with the Poincaré half-plane model is

In [73]:
Phi4 = H2.diff_mapping(R3, {(X_hplane, X3): [1, x, y]},
                       name='Phi_4', latex_name=r'\Phi_4')
Phi4.display()
Out[73]:
In [74]:
graph_hplane = X_pol.plot(X3, mapping=Phi4.restrict(U), ranges={r: (0, 1.5)}, nb_values=15, 
                          color='brown', label_axes=False)
show(graph_hyp + graph_Pdisk + graph_spher + graph_hplane, aspect_ratio=1, viewer=viewer3D,
     figsize=8)

Let us draw the grid of the hyperboloidal coordinates $(r,\varphi)$ in terms of the half-plane coordinates $(x,y)$:

In [75]:
pol_to_hplane = Pdisk_to_hplane * pol_to_Pdisk
In [76]:
show(X_pol.plot(X_hplane, ranges={r: (0,24)}, style={r: '-', ph: '--'}, nb_values=15, 
                plot_points=200, color='brown'), xmin=-5, xmax=5, ymin=0, ymax=5, aspect_ratio=1)

The solid curves are those along which $r$ varies while $\varphi$ is kept constant. Conversely, the dashed curves are those along which $\varphi$ varies, while $r$ is kept constant. We notice that the former curves are arcs of circles orthogonal to the half-plane boundary $y=0$, hence they are geodesics of $(\mathbb{H}^2,g)$. This is not surprising since they correspond to the intersections of the hyperboloid with planes through the origin (namely the plane $\varphi=\mathrm{const}$). The point $(x,y) = (0,2)$ corresponds to $r=0$.

We may also depict the Poincaré disk coordinates $(u,v)$ in terms of the half-plane coordinates $(x,y)$:

In [77]:
X_Pdisk_cart.plot(ranges={u: (-1, 0), v: (-1, 0)}, 
                  style={u: '-', v: '--'}) + \
X_Pdisk_cart.plot(ranges={u: (-1, 0), v: (0., 1)}, 
                  style={u: '-', v: '--'}, color='orange') + \
X_Pdisk_cart.plot(ranges={u: (0, 1), v: (-1, 0)}, 
                    style={u: '-', v: '--'}, color='pink') + \
X_Pdisk_cart.plot(ranges={u: (0, 1), v: (0, 1)}, 
                  style={u: '-', v: '--'}, color='violet')
Out[77]:
In [78]:
show(X_Pdisk_cart.plot(X_hplane, ranges={u: (-1, 0), v: (-1, 0)}, 
                       style={u: '-', v: '--'}) + \
     X_Pdisk_cart.plot(X_hplane, ranges={u: (-1, 0), v: (0, 1)}, 
                       style={u: '-', v: '--'}, color='orange') + \
     X_Pdisk_cart.plot(X_hplane, ranges={u: (0, 1), v: (-1, 0)}, 
                       style={u: '-', v: '--'}, color='pink') + \
     X_Pdisk_cart.plot(X_hplane, ranges={u: (0, 1), v: (0, 1)}, 
                       style={u: '-', v: '--'}, color='violet'),
     xmin=-5, xmax=5, ymin=0, ymax=5, aspect_ratio=1)