Hyperbolic Geodesics

This module implements the abstract base class for geodesics in hyperbolic space of arbitrary dimension. It also contains the implementations for specific models of hyperbolic geometry.

AUTHORS:

  • Greg Laun (2013): initial version

EXAMPLES:

We can construct geodesics in the upper half plane model, abbreviated UHP for convenience:

sage: g = HyperbolicPlane().UHP().get_geodesic(2, 3)
sage: g
Geodesic in UHP from 2 to 3
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(Integer(2), Integer(3))
>>> g
Geodesic in UHP from 2 to 3
g = HyperbolicPlane().UHP().get_geodesic(2, 3)
g

This geodesic can be plotted using plot(), in this example we will show the axis.

sage: g.plot(axes=True)                                                             # needs sage.plot
Graphics object consisting of 2 graphics primitives
>>> from sage.all import *
>>> g.plot(axes=True)                                                             # needs sage.plot
Graphics object consisting of 2 graphics primitives
g.plot(axes=True)                                                             # needs sage.plot
../../../_images/hyperbolic_geodesic-1.svg
sage: g = HyperbolicPlane().UHP().get_geodesic(I, 3 + I)
sage: g.length()
arccosh(11/2)
sage: g.plot(axes=True)                                                             # needs sage.plot
Graphics object consisting of 2 graphics primitives
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(I, Integer(3) + I)
>>> g.length()
arccosh(11/2)
>>> g.plot(axes=True)                                                             # needs sage.plot
Graphics object consisting of 2 graphics primitives
g = HyperbolicPlane().UHP().get_geodesic(I, 3 + I)
g.length()
g.plot(axes=True)                                                             # needs sage.plot
../../../_images/hyperbolic_geodesic-2.svg

Geodesics of both types in UHP are supported:

sage: g = HyperbolicPlane().UHP().get_geodesic(I, 3*I)
sage: g
Geodesic in UHP from I to 3*I
sage: g.plot()                                                                      # needs sage.plot
Graphics object consisting of 2 graphics primitives
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(I, Integer(3)*I)
>>> g
Geodesic in UHP from I to 3*I
>>> g.plot()                                                                      # needs sage.plot
Graphics object consisting of 2 graphics primitives
g = HyperbolicPlane().UHP().get_geodesic(I, 3*I)
g
g.plot()                                                                      # needs sage.plot
../../../_images/hyperbolic_geodesic-3.svg

Geodesics are oriented, which means that two geodesics with the same graph will only be equal if their starting and ending points are the same:

sage: g1 = HyperbolicPlane().UHP().get_geodesic(1,2)
sage: g2 = HyperbolicPlane().UHP().get_geodesic(2,1)
sage: g1 == g2
False
>>> from sage.all import *
>>> g1 = HyperbolicPlane().UHP().get_geodesic(Integer(1),Integer(2))
>>> g2 = HyperbolicPlane().UHP().get_geodesic(Integer(2),Integer(1))
>>> g1 == g2
False
g1 = HyperbolicPlane().UHP().get_geodesic(1,2)
g2 = HyperbolicPlane().UHP().get_geodesic(2,1)
g1 == g2

Todo

Implement a parent for all geodesics of the hyperbolic plane? Or implement geodesics as a parent in the subobjects category?

class sage.geometry.hyperbolic_space.hyperbolic_geodesic.HyperbolicGeodesic(model, start, end, **graphics_options)[source]

Bases: SageObject

Abstract base class for oriented geodesics that are not necessarily complete.

INPUT:

  • start – a HyperbolicPoint or coordinates of a point in hyperbolic space representing the start of the geodesic

  • end – a HyperbolicPoint or coordinates of a point in hyperbolic space representing the end of the geodesic

EXAMPLES:

We can construct a hyperbolic geodesic in any model:

sage: HyperbolicPlane().UHP().get_geodesic(1, 0)
Geodesic in UHP from 1 to 0
sage: HyperbolicPlane().PD().get_geodesic(1, 0)
Geodesic in PD from 1 to 0
sage: HyperbolicPlane().KM().get_geodesic((0,1/2), (1/2, 0))
Geodesic in KM from (0, 1/2) to (1/2, 0)
sage: HyperbolicPlane().HM().get_geodesic((0,0,1), (0,1, sqrt(2)))
Geodesic in HM from (0, 0, 1) to (0, 1, sqrt(2))
>>> from sage.all import *
>>> HyperbolicPlane().UHP().get_geodesic(Integer(1), Integer(0))
Geodesic in UHP from 1 to 0
>>> HyperbolicPlane().PD().get_geodesic(Integer(1), Integer(0))
Geodesic in PD from 1 to 0
>>> HyperbolicPlane().KM().get_geodesic((Integer(0),Integer(1)/Integer(2)), (Integer(1)/Integer(2), Integer(0)))
Geodesic in KM from (0, 1/2) to (1/2, 0)
>>> HyperbolicPlane().HM().get_geodesic((Integer(0),Integer(0),Integer(1)), (Integer(0),Integer(1), sqrt(Integer(2))))
Geodesic in HM from (0, 0, 1) to (0, 1, sqrt(2))
HyperbolicPlane().UHP().get_geodesic(1, 0)
HyperbolicPlane().PD().get_geodesic(1, 0)
HyperbolicPlane().KM().get_geodesic((0,1/2), (1/2, 0))
HyperbolicPlane().HM().get_geodesic((0,0,1), (0,1, sqrt(2)))
angle(other)[source]

Return the angle between any two given geodesics if they intersect.

INPUT:

  • other – a hyperbolic geodesic in the same model as self

OUTPUT: the angle in radians between the two given geodesics

EXAMPLES:

sage: PD = HyperbolicPlane().PD()
sage: g = PD.get_geodesic(3/5*I + 4/5, 15/17*I + 8/17)
sage: h = PD.get_geodesic(4/5*I + 3/5, I)
sage: g.angle(h)
1/2*pi
>>> from sage.all import *
>>> PD = HyperbolicPlane().PD()
>>> g = PD.get_geodesic(Integer(3)/Integer(5)*I + Integer(4)/Integer(5), Integer(15)/Integer(17)*I + Integer(8)/Integer(17))
>>> h = PD.get_geodesic(Integer(4)/Integer(5)*I + Integer(3)/Integer(5), I)
>>> g.angle(h)
1/2*pi
PD = HyperbolicPlane().PD()
g = PD.get_geodesic(3/5*I + 4/5, 15/17*I + 8/17)
h = PD.get_geodesic(4/5*I + 3/5, I)
g.angle(h)
../../../_images/hyperbolic_geodesic-4.svg
common_perpendicula(other)[source]

Return the unique hyperbolic geodesic perpendicular to two given geodesics, if such a geodesic exists. If none exists, raise a ValueError.

INPUT:

  • other – a hyperbolic geodesic in the same model as self

OUTPUT: a hyperbolic geodesic

EXAMPLES:

sage: g = HyperbolicPlane().UHP().get_geodesic(2,3)
sage: h = HyperbolicPlane().UHP().get_geodesic(4,5)
sage: g.common_perpendicular(h)
Geodesic in UHP from 1/2*sqrt(3) + 7/2 to -1/2*sqrt(3) + 7/2
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(Integer(2),Integer(3))
>>> h = HyperbolicPlane().UHP().get_geodesic(Integer(4),Integer(5))
>>> g.common_perpendicular(h)
Geodesic in UHP from 1/2*sqrt(3) + 7/2 to -1/2*sqrt(3) + 7/2
g = HyperbolicPlane().UHP().get_geodesic(2,3)
h = HyperbolicPlane().UHP().get_geodesic(4,5)
g.common_perpendicular(h)
../../../_images/hyperbolic_geodesic-5.svg

It is an error to ask for the common perpendicular of two intersecting geodesics:

sage: g = HyperbolicPlane().UHP().get_geodesic(2,4)
sage: h = HyperbolicPlane().UHP().get_geodesic(3, infinity)
sage: g.common_perpendicular(h)
Traceback (most recent call last):
...
ValueError: geodesics intersect; no common perpendicular exists
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(Integer(2),Integer(4))
>>> h = HyperbolicPlane().UHP().get_geodesic(Integer(3), infinity)
>>> g.common_perpendicular(h)
Traceback (most recent call last):
...
ValueError: geodesics intersect; no common perpendicular exists
g = HyperbolicPlane().UHP().get_geodesic(2,4)
h = HyperbolicPlane().UHP().get_geodesic(3, infinity)
g.common_perpendicular(h)
complete()[source]

Return the geodesic with ideal endpoints in bounded models. Raise a NotImplementedError in models that are not bounded. In the following examples we represent complete geodesics by a dashed line.

EXAMPLES:

sage: H = HyperbolicPlane()
sage: UHP = H.UHP()
sage: UHP.get_geodesic(1 + I, 1 + 3*I).complete()
Geodesic in UHP from 1 to +Infinity
>>> from sage.all import *
>>> H = HyperbolicPlane()
>>> UHP = H.UHP()
>>> UHP.get_geodesic(Integer(1) + I, Integer(1) + Integer(3)*I).complete()
Geodesic in UHP from 1 to +Infinity
H = HyperbolicPlane()
UHP = H.UHP()
UHP.get_geodesic(1 + I, 1 + 3*I).complete()
../../../_images/hyperbolic_geodesic-6.svg
sage: PD = H.PD()
sage: PD.get_geodesic(0, I/2).complete()
Geodesic in PD from -I to I
sage: PD.get_geodesic(0.25*(-1-I),0.25*(1-I)).complete()
Geodesic in PD from -0.895806416477617 - 0.444444444444444*I to 0.895806416477617 - 0.444444444444444*I
>>> from sage.all import *
>>> PD = H.PD()
>>> PD.get_geodesic(Integer(0), I/Integer(2)).complete()
Geodesic in PD from -I to I
>>> PD.get_geodesic(RealNumber('0.25')*(-Integer(1)-I),RealNumber('0.25')*(Integer(1)-I)).complete()
Geodesic in PD from -0.895806416477617 - 0.444444444444444*I to 0.895806416477617 - 0.444444444444444*I
PD = H.PD()
PD.get_geodesic(0, I/2).complete()
PD.get_geodesic(0.25*(-1-I),0.25*(1-I)).complete()
../../../_images/hyperbolic_geodesic-7.svg
sage: KM = H.KM()
sage: KM.get_geodesic((0,0), (0,1/2)).complete()
Geodesic in KM from (0, -1) to (0, 1)
>>> from sage.all import *
>>> KM = H.KM()
>>> KM.get_geodesic((Integer(0),Integer(0)), (Integer(0),Integer(1)/Integer(2))).complete()
Geodesic in KM from (0, -1) to (0, 1)
KM = H.KM()
KM.get_geodesic((0,0), (0,1/2)).complete()
../../../_images/hyperbolic_geodesic-8.svg
sage: KM.get_geodesic(-I, 1).complete()
Geodesic in KM from -I to 1
>>> from sage.all import *
>>> KM.get_geodesic(-I, Integer(1)).complete()
Geodesic in KM from -I to 1
KM.get_geodesic(-I, 1).complete()
../../../_images/hyperbolic_geodesic-9.svg
sage: HM = H.HM()
sage: HM.get_geodesic((0,0,1), (1, 0, sqrt(2))).complete()
Geodesic in HM from (0, 0, 1) to (1, 0, sqrt(2))
>>> from sage.all import *
>>> HM = H.HM()
>>> HM.get_geodesic((Integer(0),Integer(0),Integer(1)), (Integer(1), Integer(0), sqrt(Integer(2)))).complete()
Geodesic in HM from (0, 0, 1) to (1, 0, sqrt(2))
HM = H.HM()
HM.get_geodesic((0,0,1), (1, 0, sqrt(2))).complete()
../../../_images/hyperbolic_geodesic-10.svg
sage: g = HM.get_geodesic((0,0,1), (1, 0, sqrt(2))).complete()
sage: g.is_complete()
True
>>> from sage.all import *
>>> g = HM.get_geodesic((Integer(0),Integer(0),Integer(1)), (Integer(1), Integer(0), sqrt(Integer(2)))).complete()
>>> g.is_complete()
True
g = HM.get_geodesic((0,0,1), (1, 0, sqrt(2))).complete()
g.is_complete()
dist(other)[source]

Return the hyperbolic distance from a given hyperbolic geodesic to another geodesic or point.

INPUT:

  • other – a hyperbolic geodesic or hyperbolic point in the same model

OUTPUT: the hyperbolic distance

EXAMPLES:

sage: g = HyperbolicPlane().UHP().get_geodesic(2, 4.0)
sage: h = HyperbolicPlane().UHP().get_geodesic(5, 7.0)
sage: bool(abs(g.dist(h).n() - 1.92484730023841) < 10**-9)
True
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(Integer(2), RealNumber('4.0'))
>>> h = HyperbolicPlane().UHP().get_geodesic(Integer(5), RealNumber('7.0'))
>>> bool(abs(g.dist(h).n() - RealNumber('1.92484730023841')) < Integer(10)**-Integer(9))
True
g = HyperbolicPlane().UHP().get_geodesic(2, 4.0)
h = HyperbolicPlane().UHP().get_geodesic(5, 7.0)
bool(abs(g.dist(h).n() - 1.92484730023841) < 10**-9)

If the second object is a geodesic ultraparallel to the first, or if it is a point on the boundary that is not one of the first object’s endpoints, then return +infinity

sage: g = HyperbolicPlane().UHP().get_geodesic(2, 2+I)
sage: p = HyperbolicPlane().UHP().get_point(5)
sage: g.dist(p)
+Infinity
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(Integer(2), Integer(2)+I)
>>> p = HyperbolicPlane().UHP().get_point(Integer(5))
>>> g.dist(p)
+Infinity
g = HyperbolicPlane().UHP().get_geodesic(2, 2+I)
p = HyperbolicPlane().UHP().get_point(5)
g.dist(p)
end()[source]

Return the starting point of the geodesic.

EXAMPLES:

sage: g = HyperbolicPlane().UHP().get_geodesic(I, 3*I)
sage: g.end()
Point in UHP 3*I
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(I, Integer(3)*I)
>>> g.end()
Point in UHP 3*I
g = HyperbolicPlane().UHP().get_geodesic(I, 3*I)
g.end()
endpoints()[source]

Return a list containing the start and endpoints.

EXAMPLES:

sage: g = HyperbolicPlane().UHP().get_geodesic(I, 3*I)
sage: g.endpoints()
[Point in UHP I, Point in UHP 3*I]
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(I, Integer(3)*I)
>>> g.endpoints()
[Point in UHP I, Point in UHP 3*I]
g = HyperbolicPlane().UHP().get_geodesic(I, 3*I)
g.endpoints()
graphics_options()[source]

Return the graphics options of self.

EXAMPLES:

sage: g = HyperbolicPlane().UHP().get_geodesic(I, 2*I, color='red')
sage: g.graphics_options()
{'color': 'red'}
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(I, Integer(2)*I, color='red')
>>> g.graphics_options()
{'color': 'red'}
g = HyperbolicPlane().UHP().get_geodesic(I, 2*I, color='red')
g.graphics_options()
ideal_endpoints()[source]

Return the ideal endpoints in bounded models. Raise a NotImplementedError in models that are not bounded.

EXAMPLES:

sage: H = HyperbolicPlane()
sage: UHP = H.UHP()
sage: UHP.get_geodesic(1 + I, 1 + 3*I).ideal_endpoints()
[Boundary point in UHP 1, Boundary point in UHP +Infinity]

sage: PD = H.PD()
sage: PD.get_geodesic(0, I/2).ideal_endpoints()
[Boundary point in PD -I, Boundary point in PD I]

sage: KM = H.KM()
sage: KM.get_geodesic((0,0), (0, 1/2)).ideal_endpoints()
[Boundary point in KM (0, -1), Boundary point in KM (0, 1)]

sage: HM = H.HM()
sage: HM.get_geodesic((0,0,1), (1, 0, sqrt(2))).ideal_endpoints()
Traceback (most recent call last):
...
NotImplementedError: boundary points are not implemented in
 the HM model
>>> from sage.all import *
>>> H = HyperbolicPlane()
>>> UHP = H.UHP()
>>> UHP.get_geodesic(Integer(1) + I, Integer(1) + Integer(3)*I).ideal_endpoints()
[Boundary point in UHP 1, Boundary point in UHP +Infinity]

>>> PD = H.PD()
>>> PD.get_geodesic(Integer(0), I/Integer(2)).ideal_endpoints()
[Boundary point in PD -I, Boundary point in PD I]

>>> KM = H.KM()
>>> KM.get_geodesic((Integer(0),Integer(0)), (Integer(0), Integer(1)/Integer(2))).ideal_endpoints()
[Boundary point in KM (0, -1), Boundary point in KM (0, 1)]

>>> HM = H.HM()
>>> HM.get_geodesic((Integer(0),Integer(0),Integer(1)), (Integer(1), Integer(0), sqrt(Integer(2)))).ideal_endpoints()
Traceback (most recent call last):
...
NotImplementedError: boundary points are not implemented in
 the HM model
H = HyperbolicPlane()
UHP = H.UHP()
UHP.get_geodesic(1 + I, 1 + 3*I).ideal_endpoints()
PD = H.PD()
PD.get_geodesic(0, I/2).ideal_endpoints()
KM = H.KM()
KM.get_geodesic((0,0), (0, 1/2)).ideal_endpoints()
HM = H.HM()
HM.get_geodesic((0,0,1), (1, 0, sqrt(2))).ideal_endpoints()
intersection(other)[source]

Return the point of intersection of two geodesics (if such a point exists).

INPUT:

  • other – a hyperbolic geodesic in the same model as self

OUTPUT: a hyperbolic point or geodesic

EXAMPLES:

sage: PD = HyperbolicPlane().PD()
>>> from sage.all import *
>>> PD = HyperbolicPlane().PD()
PD = HyperbolicPlane().PD()
is_asymptotically_parallel(other)[source]

Return True if self and other are asymptotically parallel and False otherwise.

INPUT:

  • other – a hyperbolic geodesic

EXAMPLES:

sage: g = HyperbolicPlane().UHP().get_geodesic(-2,5)
sage: h = HyperbolicPlane().UHP().get_geodesic(-2,4)
sage: g.is_asymptotically_parallel(h)
True
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(-Integer(2),Integer(5))
>>> h = HyperbolicPlane().UHP().get_geodesic(-Integer(2),Integer(4))
>>> g.is_asymptotically_parallel(h)
True
g = HyperbolicPlane().UHP().get_geodesic(-2,5)
h = HyperbolicPlane().UHP().get_geodesic(-2,4)
g.is_asymptotically_parallel(h)
../../../_images/hyperbolic_geodesic-11.svg

Ultraparallel geodesics are not asymptotically parallel:

sage: g = HyperbolicPlane().UHP().get_geodesic(-2,5)
sage: h = HyperbolicPlane().UHP().get_geodesic(-1,4)
sage: g.is_asymptotically_parallel(h)
False
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(-Integer(2),Integer(5))
>>> h = HyperbolicPlane().UHP().get_geodesic(-Integer(1),Integer(4))
>>> g.is_asymptotically_parallel(h)
False
g = HyperbolicPlane().UHP().get_geodesic(-2,5)
h = HyperbolicPlane().UHP().get_geodesic(-1,4)
g.is_asymptotically_parallel(h)
../../../_images/hyperbolic_geodesic-12.svg

No hyperbolic geodesic is asymptotically parallel to itself:

sage: g = HyperbolicPlane().UHP().get_geodesic(-2,5)
sage: g.is_asymptotically_parallel(g)
False
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(-Integer(2),Integer(5))
>>> g.is_asymptotically_parallel(g)
False
g = HyperbolicPlane().UHP().get_geodesic(-2,5)
g.is_asymptotically_parallel(g)
is_complete()[source]

Return True if self is a complete geodesic (that is, both endpoints are on the ideal boundary) and False otherwise.

If we represent complete geodesics using green color and incomplete using red colors we have the following graphic:

../../../_images/hyperbolic_geodesic-13.svg

Notice, that there is no visual indication that the vertical geodesic is complete

EXAMPLES:

sage: UHP = HyperbolicPlane().UHP()
sage: UHP.get_geodesic(1.5*I, 2.5*I).is_complete()
False
sage: UHP.get_geodesic(0, I).is_complete()
False
sage: UHP.get_geodesic(3, infinity).is_complete()
True
sage: UHP.get_geodesic(2,5).is_complete()
True
>>> from sage.all import *
>>> UHP = HyperbolicPlane().UHP()
>>> UHP.get_geodesic(RealNumber('1.5')*I, RealNumber('2.5')*I).is_complete()
False
>>> UHP.get_geodesic(Integer(0), I).is_complete()
False
>>> UHP.get_geodesic(Integer(3), infinity).is_complete()
True
>>> UHP.get_geodesic(Integer(2),Integer(5)).is_complete()
True
UHP = HyperbolicPlane().UHP()
UHP.get_geodesic(1.5*I, 2.5*I).is_complete()
UHP.get_geodesic(0, I).is_complete()
UHP.get_geodesic(3, infinity).is_complete()
UHP.get_geodesic(2,5).is_complete()
is_parallel(other)[source]

Return True if the two given hyperbolic geodesics are either ultra parallel or asymptotically parallel and``False`` otherwise.

INPUT:

  • other – a hyperbolic geodesic in any model

OUTPUT:

True if the given geodesics are either ultra parallel or asymptotically parallel, False if not.

EXAMPLES:

sage: g = HyperbolicPlane().UHP().get_geodesic(-2,5)
sage: h = HyperbolicPlane().UHP().get_geodesic(5,12)
sage: g.is_parallel(h)
True
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(-Integer(2),Integer(5))
>>> h = HyperbolicPlane().UHP().get_geodesic(Integer(5),Integer(12))
>>> g.is_parallel(h)
True
g = HyperbolicPlane().UHP().get_geodesic(-2,5)
h = HyperbolicPlane().UHP().get_geodesic(5,12)
g.is_parallel(h)
../../../_images/hyperbolic_geodesic-14.svg
sage: g = HyperbolicPlane().UHP().get_geodesic(-2,5)
sage: h = HyperbolicPlane().UHP().get_geodesic(-2,4)
sage: g.is_parallel(h)
True
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(-Integer(2),Integer(5))
>>> h = HyperbolicPlane().UHP().get_geodesic(-Integer(2),Integer(4))
>>> g.is_parallel(h)
True
g = HyperbolicPlane().UHP().get_geodesic(-2,5)
h = HyperbolicPlane().UHP().get_geodesic(-2,4)
g.is_parallel(h)
../../../_images/hyperbolic_geodesic-15.svg
sage: g = HyperbolicPlane().UHP().get_geodesic(-2,2)
sage: h = HyperbolicPlane().UHP().get_geodesic(-1,4)
sage: g.is_parallel(h)
False
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(-Integer(2),Integer(2))
>>> h = HyperbolicPlane().UHP().get_geodesic(-Integer(1),Integer(4))
>>> g.is_parallel(h)
False
g = HyperbolicPlane().UHP().get_geodesic(-2,2)
h = HyperbolicPlane().UHP().get_geodesic(-1,4)
g.is_parallel(h)
../../../_images/hyperbolic_geodesic-16.svg

No hyperbolic geodesic is either ultra parallel or asymptotically parallel to itself:

sage: g = HyperbolicPlane().UHP().get_geodesic(-2,5)
sage: g.is_parallel(g)
False
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(-Integer(2),Integer(5))
>>> g.is_parallel(g)
False
g = HyperbolicPlane().UHP().get_geodesic(-2,5)
g.is_parallel(g)
is_ultra_parallel(other)[source]

Return True if self and other are ultra parallel and False otherwise.

INPUT:

  • other – a hyperbolic geodesic

EXAMPLES:

sage: from sage.geometry.hyperbolic_space.hyperbolic_geodesic \
....:   import *
sage: g = HyperbolicPlane().UHP().get_geodesic(0,1)
sage: h = HyperbolicPlane().UHP().get_geodesic(-3,-1)
sage: g.is_ultra_parallel(h)
True
>>> from sage.all import *
>>> from sage.geometry.hyperbolic_space.hyperbolic_geodesic   import *
>>> g = HyperbolicPlane().UHP().get_geodesic(Integer(0),Integer(1))
>>> h = HyperbolicPlane().UHP().get_geodesic(-Integer(3),-Integer(1))
>>> g.is_ultra_parallel(h)
True
from sage.geometry.hyperbolic_space.hyperbolic_geodesic \
  import *
g = HyperbolicPlane().UHP().get_geodesic(0,1)
h = HyperbolicPlane().UHP().get_geodesic(-3,-1)
g.is_ultra_parallel(h)
../../../_images/hyperbolic_geodesic-17.svg
sage: g = HyperbolicPlane().UHP().get_geodesic(-2,5)
sage: h = HyperbolicPlane().UHP().get_geodesic(2,6)
sage: g.is_ultra_parallel(h)
False
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(-Integer(2),Integer(5))
>>> h = HyperbolicPlane().UHP().get_geodesic(Integer(2),Integer(6))
>>> g.is_ultra_parallel(h)
False
g = HyperbolicPlane().UHP().get_geodesic(-2,5)
h = HyperbolicPlane().UHP().get_geodesic(2,6)
g.is_ultra_parallel(h)
../../../_images/hyperbolic_geodesic-18.svg
sage: g = HyperbolicPlane().UHP().get_geodesic(-2,5)
sage: g.is_ultra_parallel(g)
False
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(-Integer(2),Integer(5))
>>> g.is_ultra_parallel(g)
False
g = HyperbolicPlane().UHP().get_geodesic(-2,5)
g.is_ultra_parallel(g)
length()[source]

Return the Hyperbolic length of the hyperbolic line segment.

EXAMPLES:

sage: g = HyperbolicPlane().UHP().get_geodesic(2 + I, 3 + I/2)
sage: g.length()
arccosh(9/4)
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(Integer(2) + I, Integer(3) + I/Integer(2))
>>> g.length()
arccosh(9/4)
g = HyperbolicPlane().UHP().get_geodesic(2 + I, 3 + I/2)
g.length()
midpoint()[source]

Return the (hyperbolic) midpoint of a hyperbolic line segment.

EXAMPLES:

sage: g = HyperbolicPlane().UHP().random_geodesic()
sage: m = g.midpoint()
sage: end1, end2 = g.endpoints()
sage: bool(abs(m.dist(end1) - m.dist(end2)) < 10**-9)
True
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().random_geodesic()
>>> m = g.midpoint()
>>> end1, end2 = g.endpoints()
>>> bool(abs(m.dist(end1) - m.dist(end2)) < Integer(10)**-Integer(9))
True
g = HyperbolicPlane().UHP().random_geodesic()
m = g.midpoint()
end1, end2 = g.endpoints()
bool(abs(m.dist(end1) - m.dist(end2)) < 10**-9)

Complete geodesics have no midpoint:

sage: HyperbolicPlane().UHP().get_geodesic(0,2).midpoint()
Traceback (most recent call last):
...
ValueError: the length must be finite
>>> from sage.all import *
>>> HyperbolicPlane().UHP().get_geodesic(Integer(0),Integer(2)).midpoint()
Traceback (most recent call last):
...
ValueError: the length must be finite
HyperbolicPlane().UHP().get_geodesic(0,2).midpoint()
model()[source]

Return the model to which the HyperbolicGeodesic belongs.

EXAMPLES:

sage: UHP = HyperbolicPlane().UHP()
sage: UHP.get_geodesic(I, 2*I).model()
Hyperbolic plane in the Upper Half Plane Model

sage: PD = HyperbolicPlane().PD()
sage: PD.get_geodesic(0, I/2).model()
Hyperbolic plane in the Poincare Disk Model

sage: KM = HyperbolicPlane().KM()
sage: KM.get_geodesic((0, 0), (0, 1/2)).model()
Hyperbolic plane in the Klein Disk Model

sage: HM = HyperbolicPlane().HM()
sage: HM.get_geodesic((0, 0, 1), (0, 1, sqrt(2))).model()
Hyperbolic plane in the Hyperboloid Model
>>> from sage.all import *
>>> UHP = HyperbolicPlane().UHP()
>>> UHP.get_geodesic(I, Integer(2)*I).model()
Hyperbolic plane in the Upper Half Plane Model

>>> PD = HyperbolicPlane().PD()
>>> PD.get_geodesic(Integer(0), I/Integer(2)).model()
Hyperbolic plane in the Poincare Disk Model

>>> KM = HyperbolicPlane().KM()
>>> KM.get_geodesic((Integer(0), Integer(0)), (Integer(0), Integer(1)/Integer(2))).model()
Hyperbolic plane in the Klein Disk Model

>>> HM = HyperbolicPlane().HM()
>>> HM.get_geodesic((Integer(0), Integer(0), Integer(1)), (Integer(0), Integer(1), sqrt(Integer(2)))).model()
Hyperbolic plane in the Hyperboloid Model
UHP = HyperbolicPlane().UHP()
UHP.get_geodesic(I, 2*I).model()
PD = HyperbolicPlane().PD()
PD.get_geodesic(0, I/2).model()
KM = HyperbolicPlane().KM()
KM.get_geodesic((0, 0), (0, 1/2)).model()
HM = HyperbolicPlane().HM()
HM.get_geodesic((0, 0, 1), (0, 1, sqrt(2))).model()
perpendicular_bisector()[source]

Return the perpendicular bisector of self if self has finite length. Here distance is hyperbolic distance.

EXAMPLES:

sage: PD = HyperbolicPlane().PD()
sage: g = PD.get_geodesic(-0.3+0.4*I,+0.7-0.1*I)
sage: h = g.perpendicular_bisector().complete()
sage: P = g.plot(color='blue')+h.plot(color='orange');P
Graphics object consisting of 4 graphics primitives
>>> from sage.all import *
>>> PD = HyperbolicPlane().PD()
>>> g = PD.get_geodesic(-RealNumber('0.3')+RealNumber('0.4')*I,+RealNumber('0.7')-RealNumber('0.1')*I)
>>> h = g.perpendicular_bisector().complete()
>>> P = g.plot(color='blue')+h.plot(color='orange');P
Graphics object consisting of 4 graphics primitives
PD = HyperbolicPlane().PD()
g = PD.get_geodesic(-0.3+0.4*I,+0.7-0.1*I)
h = g.perpendicular_bisector().complete()
P = g.plot(color='blue')+h.plot(color='orange');P
../../../_images/hyperbolic_geodesic-19.svg

Complete geodesics cannot be bisected:

sage: g = HyperbolicPlane().PD().get_geodesic(0, 1)
sage: g.perpendicular_bisector()
Traceback (most recent call last):
...
ValueError: the length must be finite
>>> from sage.all import *
>>> g = HyperbolicPlane().PD().get_geodesic(Integer(0), Integer(1))
>>> g.perpendicular_bisector()
Traceback (most recent call last):
...
ValueError: the length must be finite
g = HyperbolicPlane().PD().get_geodesic(0, 1)
g.perpendicular_bisector()
reflection_involution()[source]

Return the involution fixing self.

EXAMPLES:

sage: H = HyperbolicPlane()
sage: gU = H.UHP().get_geodesic(2,4)
sage: RU = gU.reflection_involution(); RU
Isometry in UHP
[ 3 -8]
[ 1 -3]

sage: RU*gU == gU
True

sage: gP = H.PD().get_geodesic(0, I)
sage: RP = gP.reflection_involution(); RP
Isometry in PD
[ 1  0]
[ 0 -1]

sage: RP*gP == gP
True

sage: gK = H.KM().get_geodesic((0,0), (0,1))
sage: RK = gK.reflection_involution(); RK
Isometry in KM
[-1  0  0]
[ 0  1  0]
[ 0  0  1]

sage: RK*gK == gK
True

sage: HM = H.HM()
sage: g = HM.get_geodesic((0,0,1), (1,0, n(sqrt(2))))
sage: A = g.reflection_involution()
sage: B = diagonal_matrix([1, -1, 1])
sage: bool((B - A.matrix()).norm() < 10**-9)                                # needs scipy
True
>>> from sage.all import *
>>> H = HyperbolicPlane()
>>> gU = H.UHP().get_geodesic(Integer(2),Integer(4))
>>> RU = gU.reflection_involution(); RU
Isometry in UHP
[ 3 -8]
[ 1 -3]

>>> RU*gU == gU
True

>>> gP = H.PD().get_geodesic(Integer(0), I)
>>> RP = gP.reflection_involution(); RP
Isometry in PD
[ 1  0]
[ 0 -1]

>>> RP*gP == gP
True

>>> gK = H.KM().get_geodesic((Integer(0),Integer(0)), (Integer(0),Integer(1)))
>>> RK = gK.reflection_involution(); RK
Isometry in KM
[-1  0  0]
[ 0  1  0]
[ 0  0  1]

>>> RK*gK == gK
True

>>> HM = H.HM()
>>> g = HM.get_geodesic((Integer(0),Integer(0),Integer(1)), (Integer(1),Integer(0), n(sqrt(Integer(2)))))
>>> A = g.reflection_involution()
>>> B = diagonal_matrix([Integer(1), -Integer(1), Integer(1)])
>>> bool((B - A.matrix()).norm() < Integer(10)**-Integer(9))                                # needs scipy
True
H = HyperbolicPlane()
gU = H.UHP().get_geodesic(2,4)
RU = gU.reflection_involution(); RU
RU*gU == gU
gP = H.PD().get_geodesic(0, I)
RP = gP.reflection_involution(); RP
RP*gP == gP
gK = H.KM().get_geodesic((0,0), (0,1))
RK = gK.reflection_involution(); RK
RK*gK == gK
HM = H.HM()
g = HM.get_geodesic((0,0,1), (1,0, n(sqrt(2))))
A = g.reflection_involution()
B = diagonal_matrix([1, -1, 1])
bool((B - A.matrix()).norm() < 10**-9)                                # needs scipy

The above tests go through the Upper Half Plane. It remains to test that the matrices in the models do what we intend.

sage: from sage.geometry.hyperbolic_space.hyperbolic_isometry \
....:   import moebius_transform
sage: R = H.PD().get_geodesic(-1,1).reflection_involution()
sage: bool(moebius_transform(R.matrix(), 0) == 0)
True
>>> from sage.all import *
>>> from sage.geometry.hyperbolic_space.hyperbolic_isometry   import moebius_transform
>>> R = H.PD().get_geodesic(-Integer(1),Integer(1)).reflection_involution()
>>> bool(moebius_transform(R.matrix(), Integer(0)) == Integer(0))
True
from sage.geometry.hyperbolic_space.hyperbolic_isometry \
  import moebius_transform
R = H.PD().get_geodesic(-1,1).reflection_involution()
bool(moebius_transform(R.matrix(), 0) == 0)
start()[source]

Return the starting point of the geodesic.

EXAMPLES:

sage: g = HyperbolicPlane().UHP().get_geodesic(I, 3*I)
sage: g.start()
Point in UHP I
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(I, Integer(3)*I)
>>> g.start()
Point in UHP I
g = HyperbolicPlane().UHP().get_geodesic(I, 3*I)
g.start()
to_model(model)[source]

Convert the current object to image in another model.

INPUT:

  • model – the image model

EXAMPLES:

sage: UHP = HyperbolicPlane().UHP()
sage: PD = HyperbolicPlane().PD()
sage: UHP.get_geodesic(I, 2*I).to_model(PD)
Geodesic in PD from 0 to 1/3*I
sage: UHP.get_geodesic(I, 2*I).to_model('PD')
Geodesic in PD from 0 to 1/3*I
>>> from sage.all import *
>>> UHP = HyperbolicPlane().UHP()
>>> PD = HyperbolicPlane().PD()
>>> UHP.get_geodesic(I, Integer(2)*I).to_model(PD)
Geodesic in PD from 0 to 1/3*I
>>> UHP.get_geodesic(I, Integer(2)*I).to_model('PD')
Geodesic in PD from 0 to 1/3*I
UHP = HyperbolicPlane().UHP()
PD = HyperbolicPlane().PD()
UHP.get_geodesic(I, 2*I).to_model(PD)
UHP.get_geodesic(I, 2*I).to_model('PD')
update_graphics(update=False, **options)[source]

Update the graphics options of self.

INPUT:

  • update – if True, the original option are updated rather than overwritten

EXAMPLES:

sage: g = HyperbolicPlane().UHP().get_geodesic(I, 2*I)
sage: g.graphics_options()
{}

sage: g.update_graphics(color = "red"); g.graphics_options()
{'color': 'red'}

sage: g.update_graphics(color = "blue"); g.graphics_options()
{'color': 'blue'}

sage: g.update_graphics(True, size = 20); g.graphics_options()
{'color': 'blue', 'size': 20}
>>> from sage.all import *
>>> g = HyperbolicPlane().UHP().get_geodesic(I, Integer(2)*I)
>>> g.graphics_options()
{}

>>> g.update_graphics(color = "red"); g.graphics_options()
{'color': 'red'}

>>> g.update_graphics(color = "blue"); g.graphics_options()
{'color': 'blue'}

>>> g.update_graphics(True, size = Integer(20)); g.graphics_options()
{'color': 'blue', 'size': 20}
g = HyperbolicPlane().UHP().get_geodesic(I, 2*I)
g.graphics_options()
g.update_graphics(color = "red"); g.graphics_options()
g.update_graphics(color = "blue"); g.graphics_options()
g.update_graphics(True, size = 20); g.graphics_options()
class sage.geometry.hyperbolic_space.hyperbolic_geodesic.HyperbolicGeodesicHM(model, start, end, **graphics_options)[source]

Bases: HyperbolicGeodesic

A geodesic in the hyperboloid model.

Valid points in the hyperboloid model satisfy \(x^2 + y^2 - z^2 = -1\)

INPUT:

  • start – a HyperbolicPoint in hyperbolic space representing the start of the geodesic

  • end – a HyperbolicPoint in hyperbolic space representing the end of the geodesic

EXAMPLES:

sage: HM = HyperbolicPlane().HM()
sage: p1 = HM.get_point((4, -4, sqrt(33)))
sage: p2 = HM.get_point((-3,-3,sqrt(19)))
sage: g = HM.get_geodesic(p1, p2)
sage: g = HM.get_geodesic((4, -4, sqrt(33)), (-3, -3, sqrt(19)))
>>> from sage.all import *
>>> HM = HyperbolicPlane().HM()
>>> p1 = HM.get_point((Integer(4), -Integer(4), sqrt(Integer(33))))
>>> p2 = HM.get_point((-Integer(3),-Integer(3),sqrt(Integer(19))))
>>> g = HM.get_geodesic(p1, p2)
>>> g = HM.get_geodesic((Integer(4), -Integer(4), sqrt(Integer(33))), (-Integer(3), -Integer(3), sqrt(Integer(19))))
HM = HyperbolicPlane().HM()
p1 = HM.get_point((4, -4, sqrt(33)))
p2 = HM.get_point((-3,-3,sqrt(19)))
g = HM.get_geodesic(p1, p2)
g = HM.get_geodesic((4, -4, sqrt(33)), (-3, -3, sqrt(19)))
../../../_images/hyperbolic_geodesic-20.svg
plot(show_hyperboloid=True, **graphics_options)[source]

Plot self.

EXAMPLES:

sage: from sage.geometry.hyperbolic_space.hyperbolic_geodesic \
....:    import *
sage: g = HyperbolicPlane().HM().random_geodesic()
sage: g.plot()                                                              # needs sage.plot
Graphics3d Object
>>> from sage.all import *
>>> from sage.geometry.hyperbolic_space.hyperbolic_geodesic    import *
>>> g = HyperbolicPlane().HM().random_geodesic()
>>> g.plot()                                                              # needs sage.plot
Graphics3d Object
from sage.geometry.hyperbolic_space.hyperbolic_geodesic \
   import *
g = HyperbolicPlane().HM().random_geodesic()
g.plot()                                                              # needs sage.plot
../../../_images/hyperbolic_geodesic-21.svg
class sage.geometry.hyperbolic_space.hyperbolic_geodesic.HyperbolicGeodesicKM(model, start, end, **graphics_options)[source]

Bases: HyperbolicGeodesic

A geodesic in the Klein disk model.

Geodesics are represented by the chords, straight line segments with ideal endpoints on the boundary circle.

INPUT:

  • start – a HyperbolicPoint in hyperbolic space representing the start of the geodesic

  • end – a HyperbolicPoint in hyperbolic space representing the end of the geodesic

EXAMPLES:

sage: KM = HyperbolicPlane().KM()
sage: g = KM.get_geodesic((0.1,0.9),(-0.1,-0.9))
sage: h = KM.get_geodesic((-0.707106781,-0.707106781),(0.707106781,-0.707106781))
sage: P = g.plot(color='orange')+h.plot(); P                                    # needs sage.plot
Graphics object consisting of 4 graphics primitives
>>> from sage.all import *
>>> KM = HyperbolicPlane().KM()
>>> g = KM.get_geodesic((RealNumber('0.1'),RealNumber('0.9')),(-RealNumber('0.1'),-RealNumber('0.9')))
>>> h = KM.get_geodesic((-RealNumber('0.707106781'),-RealNumber('0.707106781')),(RealNumber('0.707106781'),-RealNumber('0.707106781')))
>>> P = g.plot(color='orange')+h.plot(); P                                    # needs sage.plot
Graphics object consisting of 4 graphics primitives
KM = HyperbolicPlane().KM()
g = KM.get_geodesic((0.1,0.9),(-0.1,-0.9))
h = KM.get_geodesic((-0.707106781,-0.707106781),(0.707106781,-0.707106781))
P = g.plot(color='orange')+h.plot(); P                                    # needs sage.plot
../../../_images/hyperbolic_geodesic-22.svg
plot(boundary=True, **options)[source]

Plot self.

EXAMPLES:

sage: HyperbolicPlane().KM().get_geodesic(0, 1).plot()                      # needs sage.plot
Graphics object consisting of 2 graphics primitives
>>> from sage.all import *
>>> HyperbolicPlane().KM().get_geodesic(Integer(0), Integer(1)).plot()                      # needs sage.plot
Graphics object consisting of 2 graphics primitives
HyperbolicPlane().KM().get_geodesic(0, 1).plot()                      # needs sage.plot
../../../_images/hyperbolic_geodesic-23.svg
class sage.geometry.hyperbolic_space.hyperbolic_geodesic.HyperbolicGeodesicPD(model, start, end, **graphics_options)[source]

Bases: HyperbolicGeodesic

A geodesic in the Poincaré disk model.

Geodesics in this model are represented by segments of circles contained within the unit disk that are orthogonal to the boundary of the disk, plus all diameters of the disk.

INPUT:

  • start – a HyperbolicPoint in hyperbolic space representing the start of the geodesic

  • end – a HyperbolicPoint in hyperbolic space representing the end of the geodesic

EXAMPLES:

sage: PD = HyperbolicPlane().PD()
sage: g = PD.get_geodesic(PD.get_point(I), PD.get_point(-I/2))
sage: g = PD.get_geodesic(I,-I/2)
sage: h = PD.get_geodesic(-1/2+I/2,1/2+I/2)
>>> from sage.all import *
>>> PD = HyperbolicPlane().PD()
>>> g = PD.get_geodesic(PD.get_point(I), PD.get_point(-I/Integer(2)))
>>> g = PD.get_geodesic(I,-I/Integer(2))
>>> h = PD.get_geodesic(-Integer(1)/Integer(2)+I/Integer(2),Integer(1)/Integer(2)+I/Integer(2))
PD = HyperbolicPlane().PD()
g = PD.get_geodesic(PD.get_point(I), PD.get_point(-I/2))
g = PD.get_geodesic(I,-I/2)
h = PD.get_geodesic(-1/2+I/2,1/2+I/2)
../../../_images/hyperbolic_geodesic-24.svg
plot(boundary=True, **options)[source]

Plot self.

EXAMPLES:

First some lines:

sage: PD = HyperbolicPlane().PD()
sage: PD.get_geodesic(0, 1).plot()                                          # needs sage.plot
Graphics object consisting of 2 graphics primitives
>>> from sage.all import *
>>> PD = HyperbolicPlane().PD()
>>> PD.get_geodesic(Integer(0), Integer(1)).plot()                                          # needs sage.plot
Graphics object consisting of 2 graphics primitives
PD = HyperbolicPlane().PD()
PD.get_geodesic(0, 1).plot()                                          # needs sage.plot
../../../_images/hyperbolic_geodesic-25.svg
sage: PD.get_geodesic(0, 0.3+0.8*I).plot()                                  # needs sage.plot
Graphics object consisting of 2 graphics primitives
>>> from sage.all import *
>>> PD.get_geodesic(Integer(0), RealNumber('0.3')+RealNumber('0.8')*I).plot()                                  # needs sage.plot
Graphics object consisting of 2 graphics primitives
PD.get_geodesic(0, 0.3+0.8*I).plot()                                  # needs sage.plot
../../../_images/hyperbolic_geodesic-26.svg

Then some generic geodesics:

sage: PD.get_geodesic(-0.5, 0.3+0.4*I).plot()                               # needs sage.plot
Graphics object consisting of 2 graphics primitives
sage: g = PD.get_geodesic(-1, exp(3*I*pi/7))
sage: G = g.plot(linestyle='dashed',color='red'); G                         # needs sage.plot
Graphics object consisting of 2 graphics primitives
sage: h = PD.get_geodesic(exp(2*I*pi/11), exp(1*I*pi/11))
sage: H = h.plot(thickness=6, color='orange'); H                            # needs sage.plot
Graphics object consisting of 2 graphics primitives
sage: show(G+H)                                                             # needs sage.plot
>>> from sage.all import *
>>> PD.get_geodesic(-RealNumber('0.5'), RealNumber('0.3')+RealNumber('0.4')*I).plot()                               # needs sage.plot
Graphics object consisting of 2 graphics primitives
>>> g = PD.get_geodesic(-Integer(1), exp(Integer(3)*I*pi/Integer(7)))
>>> G = g.plot(linestyle='dashed',color='red'); G                         # needs sage.plot
Graphics object consisting of 2 graphics primitives
>>> h = PD.get_geodesic(exp(Integer(2)*I*pi/Integer(11)), exp(Integer(1)*I*pi/Integer(11)))
>>> H = h.plot(thickness=Integer(6), color='orange'); H                            # needs sage.plot
Graphics object consisting of 2 graphics primitives
>>> show(G+H)                                                             # needs sage.plot
PD.get_geodesic(-0.5, 0.3+0.4*I).plot()                               # needs sage.plot
g = PD.get_geodesic(-1, exp(3*I*pi/7))
G = g.plot(linestyle='dashed',color='red'); G                         # needs sage.plot
h = PD.get_geodesic(exp(2*I*pi/11), exp(1*I*pi/11))
H = h.plot(thickness=6, color='orange'); H                            # needs sage.plot
show(G+H)                                                             # needs sage.plot
../../../_images/hyperbolic_geodesic-27.svg
class sage.geometry.hyperbolic_space.hyperbolic_geodesic.HyperbolicGeodesicUHP(model, start, end, **graphics_options)[source]

Bases: HyperbolicGeodesic

Create a geodesic in the upper half plane model.

The geodesics in this model are represented by circular arcs perpendicular to the real axis (half-circles whose origin is on the real axis) and straight vertical lines ending on the real axis.

INPUT:

  • start – a HyperbolicPoint in hyperbolic space representing the start of the geodesic

  • end – a HyperbolicPoint in hyperbolic space representing the end of the geodesic

EXAMPLES:

sage: UHP = HyperbolicPlane().UHP()
sage: g = UHP.get_geodesic(UHP.get_point(I), UHP.get_point(2 + I))
sage: g = UHP.get_geodesic(I, 2 + I)
sage: h = UHP.get_geodesic(-1, -1+2*I)
>>> from sage.all import *
>>> UHP = HyperbolicPlane().UHP()
>>> g = UHP.get_geodesic(UHP.get_point(I), UHP.get_point(Integer(2) + I))
>>> g = UHP.get_geodesic(I, Integer(2) + I)
>>> h = UHP.get_geodesic(-Integer(1), -Integer(1)+Integer(2)*I)
UHP = HyperbolicPlane().UHP()
g = UHP.get_geodesic(UHP.get_point(I), UHP.get_point(2 + I))
g = UHP.get_geodesic(I, 2 + I)
h = UHP.get_geodesic(-1, -1+2*I)
../../../_images/hyperbolic_geodesic-28.svg
angle(other)[source]

Return the angle between the completions of any two given geodesics if they intersect.

INPUT:

  • other – a hyperbolic geodesic in the UHP model

OUTPUT: the angle in radians between the two given geodesics

EXAMPLES:

sage: UHP = HyperbolicPlane().UHP()
sage: g = UHP.get_geodesic(2, 4)
sage: h = UHP.get_geodesic(3, 3 + I)
sage: g.angle(h)
1/2*pi
sage: numerical_approx(g.angle(h))
1.57079632679490
>>> from sage.all import *
>>> UHP = HyperbolicPlane().UHP()
>>> g = UHP.get_geodesic(Integer(2), Integer(4))
>>> h = UHP.get_geodesic(Integer(3), Integer(3) + I)
>>> g.angle(h)
1/2*pi
>>> numerical_approx(g.angle(h))
1.57079632679490
UHP = HyperbolicPlane().UHP()
g = UHP.get_geodesic(2, 4)
h = UHP.get_geodesic(3, 3 + I)
g.angle(h)
numerical_approx(g.angle(h))
../../../_images/hyperbolic_geodesic-29.svg

If the geodesics are identical, return angle 0:

sage: g.angle(g)
0
>>> from sage.all import *
>>> g.angle(g)
0
g.angle(g)

It is an error to ask for the angle of two geodesics that do not intersect:

sage: g = UHP.get_geodesic(2, 4)
sage: h = UHP.get_geodesic(5, 7)
sage: g.angle(h)
Traceback (most recent call last):
...
ValueError: geodesics do not intersect
>>> from sage.all import *
>>> g = UHP.get_geodesic(Integer(2), Integer(4))
>>> h = UHP.get_geodesic(Integer(5), Integer(7))
>>> g.angle(h)
Traceback (most recent call last):
...
ValueError: geodesics do not intersect
g = UHP.get_geodesic(2, 4)
h = UHP.get_geodesic(5, 7)
g.angle(h)
common_perpendicular(other)[source]

Return the unique hyperbolic geodesic perpendicular to self and other, if such a geodesic exists; otherwise raise a ValueError.

INPUT:

  • other – a hyperbolic geodesic in current model

OUTPUT: a hyperbolic geodesic

EXAMPLES:

sage: UHP = HyperbolicPlane().UHP()
sage: g = UHP.get_geodesic(2, 3)
sage: h = UHP.get_geodesic(4, 5)
sage: g.common_perpendicular(h)
Geodesic in UHP from 1/2*sqrt(3) + 7/2 to -1/2*sqrt(3) + 7/2
>>> from sage.all import *
>>> UHP = HyperbolicPlane().UHP()
>>> g = UHP.get_geodesic(Integer(2), Integer(3))
>>> h = UHP.get_geodesic(Integer(4), Integer(5))
>>> g.common_perpendicular(h)
Geodesic in UHP from 1/2*sqrt(3) + 7/2 to -1/2*sqrt(3) + 7/2
UHP = HyperbolicPlane().UHP()
g = UHP.get_geodesic(2, 3)
h = UHP.get_geodesic(4, 5)
g.common_perpendicular(h)
../../../_images/hyperbolic_geodesic-30.svg

It is an error to ask for the common perpendicular of two intersecting geodesics:

sage: g = UHP.get_geodesic(2, 4)
sage: h = UHP.get_geodesic(3, infinity)
sage: g.common_perpendicular(h)
Traceback (most recent call last):
...
ValueError: geodesics intersect; no common perpendicular exists
>>> from sage.all import *
>>> g = UHP.get_geodesic(Integer(2), Integer(4))
>>> h = UHP.get_geodesic(Integer(3), infinity)
>>> g.common_perpendicular(h)
Traceback (most recent call last):
...
ValueError: geodesics intersect; no common perpendicular exists
g = UHP.get_geodesic(2, 4)
h = UHP.get_geodesic(3, infinity)
g.common_perpendicular(h)
ideal_endpoints()[source]

Determine the ideal (boundary) endpoints of the complete hyperbolic geodesic corresponding to self.

OUTPUT: list of 2 boundary points

EXAMPLES:

sage: UHP = HyperbolicPlane().UHP()
sage: UHP.get_geodesic(I, 2*I).ideal_endpoints()
[Boundary point in UHP 0,
 Boundary point in UHP +Infinity]
sage: UHP.get_geodesic(1 + I, 2 + 4*I).ideal_endpoints()
[Boundary point in UHP -sqrt(65) + 9,
 Boundary point in UHP sqrt(65) + 9]
>>> from sage.all import *
>>> UHP = HyperbolicPlane().UHP()
>>> UHP.get_geodesic(I, Integer(2)*I).ideal_endpoints()
[Boundary point in UHP 0,
 Boundary point in UHP +Infinity]
>>> UHP.get_geodesic(Integer(1) + I, Integer(2) + Integer(4)*I).ideal_endpoints()
[Boundary point in UHP -sqrt(65) + 9,
 Boundary point in UHP sqrt(65) + 9]
UHP = HyperbolicPlane().UHP()
UHP.get_geodesic(I, 2*I).ideal_endpoints()
UHP.get_geodesic(1 + I, 2 + 4*I).ideal_endpoints()
intersection(other)[source]

Return the point of intersection of self and other (if such a point exists).

INPUT:

  • other – a hyperbolic geodesic in the current model

OUTPUT: list of hyperbolic points or a hyperbolic geodesic

EXAMPLES:

sage: UHP = HyperbolicPlane().UHP()
sage: g = UHP.get_geodesic(3, 5)
sage: h = UHP.get_geodesic(4, 7)
sage: g.intersection(h)
[Point in UHP 2/3*sqrt(-2) + 13/3]
>>> from sage.all import *
>>> UHP = HyperbolicPlane().UHP()
>>> g = UHP.get_geodesic(Integer(3), Integer(5))
>>> h = UHP.get_geodesic(Integer(4), Integer(7))
>>> g.intersection(h)
[Point in UHP 2/3*sqrt(-2) + 13/3]
UHP = HyperbolicPlane().UHP()
g = UHP.get_geodesic(3, 5)
h = UHP.get_geodesic(4, 7)
g.intersection(h)
../../../_images/hyperbolic_geodesic-31.svg

If the given geodesics do not intersect, the function returns an empty list:

sage: g = UHP.get_geodesic(4, 5)
sage: h = UHP.get_geodesic(6, 7)
sage: g.intersection(h)
[]
>>> from sage.all import *
>>> g = UHP.get_geodesic(Integer(4), Integer(5))
>>> h = UHP.get_geodesic(Integer(6), Integer(7))
>>> g.intersection(h)
[]
g = UHP.get_geodesic(4, 5)
h = UHP.get_geodesic(6, 7)
g.intersection(h)
../../../_images/hyperbolic_geodesic-32.svg

If the given geodesics are asymptotically parallel, the function returns the common boundary point:

sage: g = UHP.get_geodesic(4, 5)
sage: h = UHP.get_geodesic(5, 7)
sage: g.intersection(h)
[Boundary point in UHP 5.00000000000000]
>>> from sage.all import *
>>> g = UHP.get_geodesic(Integer(4), Integer(5))
>>> h = UHP.get_geodesic(Integer(5), Integer(7))
>>> g.intersection(h)
[Boundary point in UHP 5.00000000000000]
g = UHP.get_geodesic(4, 5)
h = UHP.get_geodesic(5, 7)
g.intersection(h)
../../../_images/hyperbolic_geodesic-33.svg

If the given geodesics are identical, return that geodesic:

sage: g = UHP.get_geodesic(4 + I, 18*I)
sage: h = UHP.get_geodesic(4 + I, 18*I)
sage: g.intersection(h)
Geodesic in UHP from I + 4 to 18*I
>>> from sage.all import *
>>> g = UHP.get_geodesic(Integer(4) + I, Integer(18)*I)
>>> h = UHP.get_geodesic(Integer(4) + I, Integer(18)*I)
>>> g.intersection(h)
Geodesic in UHP from I + 4 to 18*I
g = UHP.get_geodesic(4 + I, 18*I)
h = UHP.get_geodesic(4 + I, 18*I)
g.intersection(h)
midpoint()[source]

Return the (hyperbolic) midpoint of self if it exists.

EXAMPLES:

sage: UHP = HyperbolicPlane().UHP()
sage: g = UHP.random_geodesic()
sage: m = g.midpoint()
sage: d1 = UHP.dist(m, g.start())
sage: d2 = UHP.dist(m, g.end())
sage: bool(abs(d1 - d2) < 10**-9)
True
>>> from sage.all import *
>>> UHP = HyperbolicPlane().UHP()
>>> g = UHP.random_geodesic()
>>> m = g.midpoint()
>>> d1 = UHP.dist(m, g.start())
>>> d2 = UHP.dist(m, g.end())
>>> bool(abs(d1 - d2) < Integer(10)**-Integer(9))
True
UHP = HyperbolicPlane().UHP()
g = UHP.random_geodesic()
m = g.midpoint()
d1 = UHP.dist(m, g.start())
d2 = UHP.dist(m, g.end())
bool(abs(d1 - d2) < 10**-9)

Infinite geodesics have no midpoint:

sage: UHP.get_geodesic(0, 2).midpoint()
Traceback (most recent call last):
...
ValueError: the length must be finite
>>> from sage.all import *
>>> UHP.get_geodesic(Integer(0), Integer(2)).midpoint()
Traceback (most recent call last):
...
ValueError: the length must be finite
UHP.get_geodesic(0, 2).midpoint()
perpendicular_bisector()[source]

Return the perpendicular bisector of the hyperbolic geodesic self if that geodesic has finite length.

EXAMPLES:

sage: UHP = HyperbolicPlane().UHP()
sage: g = UHP.random_geodesic()
sage: h = g.perpendicular_bisector().complete()
sage: c = lambda x: x.coordinates()
sage: bool(c(g.intersection(h)[0]) - c(g.midpoint()) < 10**-9)
True
>>> from sage.all import *
>>> UHP = HyperbolicPlane().UHP()
>>> g = UHP.random_geodesic()
>>> h = g.perpendicular_bisector().complete()
>>> c = lambda x: x.coordinates()
>>> bool(c(g.intersection(h)[Integer(0)]) - c(g.midpoint()) < Integer(10)**-Integer(9))
True
UHP = HyperbolicPlane().UHP()
g = UHP.random_geodesic()
h = g.perpendicular_bisector().complete()
c = lambda x: x.coordinates()
bool(c(g.intersection(h)[0]) - c(g.midpoint()) < 10**-9)
sage: UHP = HyperbolicPlane().UHP()
sage: g = UHP.get_geodesic(1+I,2+0.5*I)
sage: h = g.perpendicular_bisector().complete()
sage: show(g.plot(color='blue')+h.plot(color='orange'))
>>> from sage.all import *
>>> UHP = HyperbolicPlane().UHP()
>>> g = UHP.get_geodesic(Integer(1)+I,Integer(2)+RealNumber('0.5')*I)
>>> h = g.perpendicular_bisector().complete()
>>> show(g.plot(color='blue')+h.plot(color='orange'))
UHP = HyperbolicPlane().UHP()
g = UHP.get_geodesic(1+I,2+0.5*I)
h = g.perpendicular_bisector().complete()
show(g.plot(color='blue')+h.plot(color='orange'))
>>> from sage.all import *
>>> UHP = HyperbolicPlane().UHP()
>>> g = UHP.get_geodesic(Integer(1)+I,Integer(2)+RealNumber('0.5')*I)
>>> h = g.perpendicular_bisector().complete()
>>> show(g.plot(color='blue')+h.plot(color='orange'))
UHP = HyperbolicPlane().UHP()
g = UHP.get_geodesic(1+I,2+0.5*I)
h = g.perpendicular_bisector().complete()
show(g.plot(color='blue')+h.plot(color='orange'))
../../../_images/hyperbolic_geodesic-34.svg

Infinite geodesics cannot be bisected:

sage: UHP.get_geodesic(0, 1).perpendicular_bisector()
Traceback (most recent call last):
...
ValueError: the length must be finite
>>> from sage.all import *
>>> UHP.get_geodesic(Integer(0), Integer(1)).perpendicular_bisector()
Traceback (most recent call last):
...
ValueError: the length must be finite
UHP.get_geodesic(0, 1).perpendicular_bisector()
plot(boundary=True, **options)[source]

Plot self.

EXAMPLES:

sage: UHP = HyperbolicPlane().UHP()
sage: UHP.get_geodesic(0, 1).plot()                                         # needs sage.plot
Graphics object consisting of 2 graphics primitives
>>> from sage.all import *
>>> UHP = HyperbolicPlane().UHP()
>>> UHP.get_geodesic(Integer(0), Integer(1)).plot()                                         # needs sage.plot
Graphics object consisting of 2 graphics primitives
UHP = HyperbolicPlane().UHP()
UHP.get_geodesic(0, 1).plot()                                         # needs sage.plot
../../../_images/hyperbolic_geodesic-35.svg
sage: UHP.get_geodesic(I, 3+4*I).plot(linestyle='dashed', color='brown')    # needs sage.plot
Graphics object consisting of 2 graphics primitives
>>> from sage.all import *
>>> UHP.get_geodesic(I, Integer(3)+Integer(4)*I).plot(linestyle='dashed', color='brown')    # needs sage.plot
Graphics object consisting of 2 graphics primitives
UHP.get_geodesic(I, 3+4*I).plot(linestyle='dashed', color='brown')    # needs sage.plot
../../../_images/hyperbolic_geodesic-36.svg
sage: UHP.get_geodesic(1, infinity).plot(color='orange')                    # needs sage.plot
Graphics object consisting of 2 graphics primitives
>>> from sage.all import *
>>> UHP.get_geodesic(Integer(1), infinity).plot(color='orange')                    # needs sage.plot
Graphics object consisting of 2 graphics primitives
UHP.get_geodesic(1, infinity).plot(color='orange')                    # needs sage.plot
../../../_images/hyperbolic_geodesic-37.svg
reflection_involution()[source]

Return the isometry of the involution fixing the geodesic self.

EXAMPLES:

sage: UHP = HyperbolicPlane().UHP()
sage: g1 = UHP.get_geodesic(0, 1)
sage: g1.reflection_involution()
Isometry in UHP
[ 1  0]
[ 2 -1]
sage: UHP.get_geodesic(I, 2*I).reflection_involution()
Isometry in UHP
[ 1  0]
[ 0 -1]
>>> from sage.all import *
>>> UHP = HyperbolicPlane().UHP()
>>> g1 = UHP.get_geodesic(Integer(0), Integer(1))
>>> g1.reflection_involution()
Isometry in UHP
[ 1  0]
[ 2 -1]
>>> UHP.get_geodesic(I, Integer(2)*I).reflection_involution()
Isometry in UHP
[ 1  0]
[ 0 -1]
UHP = HyperbolicPlane().UHP()
g1 = UHP.get_geodesic(0, 1)
g1.reflection_involution()
UHP.get_geodesic(I, 2*I).reflection_involution()