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
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
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
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
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
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)) - 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 
 - 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 - 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 
 - complete()[source]¶
- Return the geodesic with ideal endpoints in bounded models. Raise a - NotImplementedErrorin 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 - 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 - 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) - 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 - 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)) - 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 
 - 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 - 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 
 - 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 
 - 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] 
 - 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'} 
 - ideal_endpoints()[source]¶
- Return the ideal endpoints in bounded models. Raise a - NotImplementedErrorin 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 
 - 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() 
 - is_asymptotically_parallel(other)[source]¶
- Return - Trueif- selfand- otherare asymptotically parallel and- Falseotherwise.- 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 - 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 - 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 
 - is_complete()[source]¶
- Return - Trueif- selfis a complete geodesic (that is, both endpoints are on the ideal boundary) and- Falseotherwise.- If we represent complete geodesics using green color and incomplete using red colors we have the following graphic: - 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 
 - is_parallel(other)[source]¶
- Return - Trueif the two given hyperbolic geodesics are either ultra parallel or asymptotically parallel and- Falseotherwise.- INPUT: - other– a hyperbolic geodesic in any model
 - OUTPUT: - Trueif the given geodesics are either ultra parallel or asymptotically parallel,- Falseif 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 - 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 - 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 - 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 
 - is_ultra_parallel(other)[source]¶
- Return - Trueif- selfand- otherare ultra parallel and- Falseotherwise.- 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 - 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 - 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 
 - 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) 
 - 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 - 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 
 - model()[source]¶
- Return the model to which the - HyperbolicGeodesicbelongs.- 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 
 - perpendicular_bisector()[source]¶
- Return the perpendicular bisector of - selfif- selfhas 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 - 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 
 - 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 - 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 
 - 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 
 - 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 
 - 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} 
 
- 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- HyperbolicPointin hyperbolic space representing the start of the geodesic
- end– a- HyperbolicPointin 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)))) - 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 
 
- 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- HyperbolicPointin hyperbolic space representing the start of the geodesic
- end– a- HyperbolicPointin 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 - 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 
 
- 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- HyperbolicPointin hyperbolic space representing the start of the geodesic
- end– a- HyperbolicPointin 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)) - 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 - 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 - 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 
 
- 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- HyperbolicPointin hyperbolic space representing the start of the geodesic
- end– a- HyperbolicPointin 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) - 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 - If the geodesics are identical, return angle 0: - sage: g.angle(g) 0 - >>> from sage.all import * >>> g.angle(g) 0 - 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 
 - common_perpendicular(other)[source]¶
- Return the unique hyperbolic geodesic perpendicular to - selfand- 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 - 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 
 - 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] 
 - intersection(other)[source]¶
- Return the point of intersection of - selfand- 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] - 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) [] - 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] - 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 
 - midpoint()[source]¶
- Return the (hyperbolic) midpoint of - selfif 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 - 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 
 - perpendicular_bisector()[source]¶
- Return the perpendicular bisector of the hyperbolic geodesic - selfif 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 - 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')) - 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 
 - 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 - 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 - 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 
 - 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]