Consider the hyperbolic plane
2

, realized in the Poincaré half-plane model. We can interpret this as the upper half-plane
(x,y)∈
2

:y>0
together with the Riemannian metric

2
s
=
1
2
y

2
x
+
2
y

.
In other words, if
U=
u
1
∂
∂x
+
u
2
∂
∂y
,V=
v
1
∂
∂x
+
v
2
∂
∂x
∈
T
(x,y)
2

, then​
〈U,V〉
(x,y)
=
u
1
v
1
2
y
+
u
2
v
2
2
y
=
1
2
y
(
u
1
v
1
+
u
2
v
2
)
.
Therefore, if
∇
is the Levi-Civita connection associated with this Riemannian metric, one can check that, using the notation
X=
∂
∂x
and
Y=
∂
∂y
,​
∇
X
X=
1
y
Y
,
∇
X
Y=
∇
Y
X=-
1
y
X
,
∇
Y
Y=-
1
y
Y
.
For more details, see Example 4.3.10 in my differential geometry notes.
Now, consider the curve
α(t)=(
y
0
t,
y
0
)
for some fixed
y
0
>0
. This is a horocycle centered at
y=∞
. It’s parametrized by arclength since
α'(t)=
y
0
X
, which is a unit vector since
∥
y
0
X
2
∥
=
〈
y
0
X,
y
0
X〉
(
y
0
t,
y
0
)
=
2
y
0
2
y
0
=1
.
If we want to parallel translate a tangent vector
W
0
at, say,
α(0)=(0,
y
0
)
, then we get a vector field
W(t)=a(t)X+b(t)Y
along the curve which satisfies the differential equation​
0=
DW
t
=
∇
α'(t)
W(t)=
∇
y
0
X
W(t)
. Here
D
t
is the covariant derivative along the curve
α
.
Expanding this out a bit, we see that​
0=
∇
y
0
X
W(t)=
∇
y
0
X
(a(t)X+b(t)Y)=
y
0
[a'(t)X+a(t)
∇
X
X+b'(t)Y+b(t)
∇
X
Y]=
y
0
a'(t)-
b(t)
y
0
X+b'(t)+
a(t)
y
0
Y
.
X
and
Y
form a basis for the tangent space at each point, so the only way for this equation to be satisfied is if both coefficients are zero, meaning that the parallel transport equation is the system of ODEs​
a'(t)-
b(t)
y
0
=0​​b'(t)+
a(t)
y
0
=0.
If we want
W
0
to be the unit vector
y
0
Y∈
T
(0,
y
0
)
2

, then we have the initial conditions
a(0)=0,b(0)=
y
0
.
Mathematica will happily solve this initial value problem:
In[]:=
DSolvea'[t]-
b[t]
y
0
==0,b'[t]+
a[t]
y
0
==0,a[0]==0,b[0]==
y
0
,{a,b},t
Out[]=
aFunction{t},Sin
t
y
0

y
0
,bFunction{t},Cos
t
y
0

y
0

Here’s a visualization showing the resulting parallel fields when
y
0
=
1
2
,1,2
:
In[]:=
GraphicsTableBlack,Thickness[.005],InfiniteLine[{{0,y0},{1,y0}}],Orange,TableArrow{y0t,y0},{y0t,y0}+y0Sin
t
y0
,Cos
t
y0
,{t,-4π,4π,2π/30},{y0,{1/2,1,2}},PlotRange->{{-π,π},{-.1,4}},Axes->True,Ticks->{Range[-π,π,π],Range[0,4]}
Out[]=
A parallel vector field is always pointing in the same direction from the perspective of someone inside the manifold, so the way to interpret this is that a person traversing the curve
α(t)=(
y
0
t,
y
0
)
is constantly turning to the left to stay on
α
. This makes sense: the geodesics (which are the straight paths) are vertical lines and semi-circles centered at points on the
x
-axis, so at each point going “straight ahead” would mean walking along the semi-circle tangent to
α
at that point. So to stay on
α
you have to turn (to the left!) away from that semi-circle.
Now we start to turn this into an animation. In all of what follows, we’ll use
y
0
=
2
3
(based on the value of this parameter that I thought gave good results in the final animation).
The arrows look a little bit too mathy, so let’s show the corresponding line field instead:
In[]:=
Withy0=
2
3
,​​GraphicsBlack,Thickness[.005],InfiniteLine[{{0,y0},{1,y0}}],Orange,TableLine{y0t,y0}-y0Sin
t
y0
,Cos
t
y0
,{y0t,y0}+y0Sin
t
y0
,Cos
t
y0
,{t,-2π,2π,2π/30},PlotRange->{{-π,π},{-.1,4/3}},Axes->True,Ticks->{Range[-π,π,π],Range[0,1]}​​
Out[]=
Which we can animate:
In[]:=
Withy0=
2
3
,​​AnimateGraphicsBlack,Thickness[.005],InfiniteLine[{{0,y0},{1,y0}}],Orange,TableLine{y0s,y0}-y0Sin
s
y0
,Cos
s
y0
,{y0s,y0}+y0Sin
s
y0
,Cos
s
y0
,{s,-2π+t,2π+t,2π/30},PlotRange->{{-π,π},{-.1,4/3}},Axes->True,Ticks->{Range[-π,π,π],Range[0,4]},{t,0,2π/30},SaveDefinitions->True,AnimationRunning->False​​
Out[]=
t
Let’s make this look a little more pleasant by shortening the lines, getting rid of the axes and underlying curve, and using some different colors (taken from this ColorHunt palette):
In[]:=
Withy0=
2
3
,cols=RGBColor/@{"#384B70","#FCFAEE"},​​AnimateGraphicsCapForm["Round"],Thickness[.0025],cols[[1]],TableLine{y0s,y0}-
y0
8
Sin
s
y0
,Cos
s
y0
,{y0s,y0}+
y0
8
Sin
s
y0
,Cos
s
y0
,{s,-2π+t,2π+t,2π/60},PlotRange->{{-2,2},{0,4/3}},Background->cols[[2]],ImageSize->600,{t,0,2π/60},SaveDefinitions->True,AnimationRunning->False​​
Out[]=
t
To produce the final animation, we’re going to transform the curve
α
(which remember was a horocycle centered at
y=∞
) to a horocycle centered at a finite point on the
x
-axis.
Recall that the Cayley transform
f(z)=
z-
z+
maps the upper half-plane model to the Poincaré disk model, and of course its inverse
-1
f
(z)=
1+z
1-z
goes the other way:
In[]:=
Cayley[z_]:=
z-I
z+I
;​​CayleyInverse[z_]:=I
1+z
1-z
;
And then we get back into the upper half-plane model by applying the inverse of the Cayley transform:
Here’s our line field from before, fed through this transformation (strictly speaking, I should really be applying the differential of the map to the vector field, but that requires more work):
Here’s the code to produce the actual GIF:

CITE THIS NOTEBOOK

Parallels (parallel translation along a horocycle)​
by Clayton Shonkwiler​
Wolfram Community, STAFF PICKS, June 3, 2025
​https://community.wolfram.com/groups/-/m/t/3473522