Hyperbolic Isometries#
This module implements the abstract base class for isometries of hyperbolic space of arbitrary dimension. It also contains the implementations for specific models of hyperbolic geometry.
The isometry groups of all implemented models are either matrix Lie groups or are doubly covered by matrix Lie groups. As such, the isometry constructor takes a matrix as input. However, since the isometries themselves may not be matrices, quantities like the trace and determinant are not directly accessible from this class.
AUTHORS:
Greg Laun (2013): initial version
EXAMPLES:
We can construct isometries in the upper half plane model, abbreviated UHP for convenience:
sage: UHP = HyperbolicPlane().UHP()
sage: UHP.get_isometry(matrix(2,[1,2,3,4]))
Isometry in UHP
[1 2]
[3 4]
sage: A = UHP.get_isometry(matrix(2,[0,1,1,0]))
sage: A.inverse()
Isometry in UHP
[0 1]
[1 0]
>>> from sage.all import *
>>> UHP = HyperbolicPlane().UHP()
>>> UHP.get_isometry(matrix(Integer(2),[Integer(1),Integer(2),Integer(3),Integer(4)]))
Isometry in UHP
[1 2]
[3 4]
>>> A = UHP.get_isometry(matrix(Integer(2),[Integer(0),Integer(1),Integer(1),Integer(0)]))
>>> A.inverse()
Isometry in UHP
[0 1]
[1 0]
- class sage.geometry.hyperbolic_space.hyperbolic_isometry.HyperbolicIsometry(model, A, check=True)[source]#
Bases:
Morphism
Abstract base class for hyperbolic isometries. This class should never be instantiated.
INPUT:
A
– a matrix representing a hyperbolic isometry in the appropriate model
EXAMPLES:
sage: HyperbolicPlane().HM().get_isometry(identity_matrix(3)) Isometry in HM [1 0 0] [0 1 0] [0 0 1]
>>> from sage.all import * >>> HyperbolicPlane().HM().get_isometry(identity_matrix(Integer(3))) Isometry in HM [1 0 0] [0 1 0] [0 0 1]
- attracting_fixed_point()[source]#
For a hyperbolic isometry, return the attracting fixed point; otherwise raise a
ValueError
.OUTPUT:
a hyperbolic point
EXAMPLES:
sage: UHP = HyperbolicPlane().UHP() sage: A = UHP.get_isometry(Matrix(2,[4,0,0,1/4])) sage: A.attracting_fixed_point() Boundary point in UHP +Infinity
>>> from sage.all import * >>> UHP = HyperbolicPlane().UHP() >>> A = UHP.get_isometry(Matrix(Integer(2),[Integer(4),Integer(0),Integer(0),Integer(1)/Integer(4)])) >>> A.attracting_fixed_point() Boundary point in UHP +Infinity
- axis()[source]#
For a hyperbolic isometry, return the axis of the transformation; otherwise raise a
ValueError
.EXAMPLES:
sage: UHP = HyperbolicPlane().UHP() sage: H = UHP.get_isometry(matrix(2,[2,0,0,1/2])) sage: H.axis() Geodesic in UHP from 0 to +Infinity
>>> from sage.all import * >>> UHP = HyperbolicPlane().UHP() >>> H = UHP.get_isometry(matrix(Integer(2),[Integer(2),Integer(0),Integer(0),Integer(1)/Integer(2)])) >>> H.axis() Geodesic in UHP from 0 to +Infinity
It is an error to call this function on an isometry that is not hyperbolic:
sage: P = UHP.get_isometry(matrix(2,[1,4,0,1])) sage: P.axis() Traceback (most recent call last): ... ValueError: the isometry is not hyperbolic: axis is undefined
>>> from sage.all import * >>> P = UHP.get_isometry(matrix(Integer(2),[Integer(1),Integer(4),Integer(0),Integer(1)])) >>> P.axis() Traceback (most recent call last): ... ValueError: the isometry is not hyperbolic: axis is undefined
- classification()[source]#
Classify the hyperbolic isometry as elliptic, parabolic, hyperbolic or a reflection.
A hyperbolic isometry fixes two points on the boundary of hyperbolic space, a parabolic isometry fixes one point on the boundary of hyperbolic space, and an elliptic isometry fixes no points.
EXAMPLES:
sage: UHP = HyperbolicPlane().UHP() sage: H = UHP.get_isometry(matrix(2,[2,0,0,1/2])) sage: H.classification() 'hyperbolic' sage: P = UHP.get_isometry(matrix(2,[1,1,0,1])) sage: P.classification() 'parabolic' sage: E = UHP.get_isometry(matrix(2,[-1,0,0,1])) sage: E.classification() 'reflection'
>>> from sage.all import * >>> UHP = HyperbolicPlane().UHP() >>> H = UHP.get_isometry(matrix(Integer(2),[Integer(2),Integer(0),Integer(0),Integer(1)/Integer(2)])) >>> H.classification() 'hyperbolic' >>> P = UHP.get_isometry(matrix(Integer(2),[Integer(1),Integer(1),Integer(0),Integer(1)])) >>> P.classification() 'parabolic' >>> E = UHP.get_isometry(matrix(Integer(2),[-Integer(1),Integer(0),Integer(0),Integer(1)])) >>> E.classification() 'reflection'
- fixed_geodesic()[source]#
If
self
is a reflection in a geodesic, return that geodesic.EXAMPLES:
sage: A = HyperbolicPlane().PD().get_isometry(matrix([[0, 1], [1, 0]])) sage: A.fixed_geodesic() Geodesic in PD from -1 to 1
>>> from sage.all import * >>> A = HyperbolicPlane().PD().get_isometry(matrix([[Integer(0), Integer(1)], [Integer(1), Integer(0)]])) >>> A.fixed_geodesic() Geodesic in PD from -1 to 1
- fixed_point_set()[source]#
Return a list containing the fixed point set of orientation-preserving isometries.
OUTPUT:
list of hyperbolic points or a hyperbolic geodesic
EXAMPLES:
sage: KM = HyperbolicPlane().KM() sage: H = KM.get_isometry(matrix([[5/3,0,4/3], [0,1,0], [4/3,0,5/3]])) sage: g = H.fixed_point_set(); g Geodesic in KM from (1, 0) to (-1, 0) sage: H(g.start()) == g.start() True sage: H(g.end()) == g.end() True sage: A = KM.get_isometry(matrix([[1,0,0], [0,-1,0], [0,0,1]])) sage: A.preserves_orientation() False sage: A.fixed_point_set() Geodesic in KM from (1, 0) to (-1, 0)
>>> from sage.all import * >>> KM = HyperbolicPlane().KM() >>> H = KM.get_isometry(matrix([[Integer(5)/Integer(3),Integer(0),Integer(4)/Integer(3)], [Integer(0),Integer(1),Integer(0)], [Integer(4)/Integer(3),Integer(0),Integer(5)/Integer(3)]])) >>> g = H.fixed_point_set(); g Geodesic in KM from (1, 0) to (-1, 0) >>> H(g.start()) == g.start() True >>> H(g.end()) == g.end() True >>> A = KM.get_isometry(matrix([[Integer(1),Integer(0),Integer(0)], [Integer(0),-Integer(1),Integer(0)], [Integer(0),Integer(0),Integer(1)]])) >>> A.preserves_orientation() False >>> A.fixed_point_set() Geodesic in KM from (1, 0) to (-1, 0)
sage: B = KM.get_isometry(identity_matrix(3)) sage: B.fixed_point_set() Traceback (most recent call last): ... ValueError: the identity transformation fixes the entire hyperbolic plane
>>> from sage.all import * >>> B = KM.get_isometry(identity_matrix(Integer(3))) >>> B.fixed_point_set() Traceback (most recent call last): ... ValueError: the identity transformation fixes the entire hyperbolic plane
- is_identity()[source]#
Return
True
ifself
is the identity isometry.EXAMPLES:
sage: UHP = HyperbolicPlane().UHP() sage: UHP.get_isometry(matrix(2,[4,1,3,2])).is_identity() False sage: UHP.get_isometry(identity_matrix(2)).is_identity() True
>>> from sage.all import * >>> UHP = HyperbolicPlane().UHP() >>> UHP.get_isometry(matrix(Integer(2),[Integer(4),Integer(1),Integer(3),Integer(2)])).is_identity() False >>> UHP.get_isometry(identity_matrix(Integer(2))).is_identity() True
- matrix()[source]#
Return the matrix of the isometry.
Note
We do not allow the
matrix
constructor to work as these may be elements of a projective group (ex. \(PSL(n, \RR)\)), so these isometries aren’t true matrices.EXAMPLES:
sage: UHP = HyperbolicPlane().UHP() sage: UHP.get_isometry(-identity_matrix(2)).matrix() [-1 0] [ 0 -1]
>>> from sage.all import * >>> UHP = HyperbolicPlane().UHP() >>> UHP.get_isometry(-identity_matrix(Integer(2))).matrix() [-1 0] [ 0 -1]
- model()[source]#
Return the model to which
self
belongs.EXAMPLES:
sage: HyperbolicPlane().UHP().get_isometry(identity_matrix(2)).model() Hyperbolic plane in the Upper Half Plane Model sage: HyperbolicPlane().PD().get_isometry(identity_matrix(2)).model() Hyperbolic plane in the Poincare Disk Model sage: HyperbolicPlane().KM().get_isometry(identity_matrix(3)).model() Hyperbolic plane in the Klein Disk Model sage: HyperbolicPlane().HM().get_isometry(identity_matrix(3)).model() Hyperbolic plane in the Hyperboloid Model
>>> from sage.all import * >>> HyperbolicPlane().UHP().get_isometry(identity_matrix(Integer(2))).model() Hyperbolic plane in the Upper Half Plane Model >>> HyperbolicPlane().PD().get_isometry(identity_matrix(Integer(2))).model() Hyperbolic plane in the Poincare Disk Model >>> HyperbolicPlane().KM().get_isometry(identity_matrix(Integer(3))).model() Hyperbolic plane in the Klein Disk Model >>> HyperbolicPlane().HM().get_isometry(identity_matrix(Integer(3))).model() Hyperbolic plane in the Hyperboloid Model
- preserves_orientation()[source]#
Return
True
ifself
is orientation-preserving andFalse
otherwise.EXAMPLES:
sage: UHP = HyperbolicPlane().UHP() sage: A = UHP.get_isometry(identity_matrix(2)) sage: A.preserves_orientation() True sage: B = UHP.get_isometry(matrix(2,[0,1,1,0])) sage: B.preserves_orientation() False
>>> from sage.all import * >>> UHP = HyperbolicPlane().UHP() >>> A = UHP.get_isometry(identity_matrix(Integer(2))) >>> A.preserves_orientation() True >>> B = UHP.get_isometry(matrix(Integer(2),[Integer(0),Integer(1),Integer(1),Integer(0)])) >>> B.preserves_orientation() False
- repelling_fixed_point()[source]#
For a hyperbolic isometry, return the attracting fixed point; otherwise raise a
ValueError
.OUTPUT:
a hyperbolic point
EXAMPLES:
sage: UHP = HyperbolicPlane().UHP() sage: A = UHP.get_isometry(Matrix(2,[4,0,0,1/4])) sage: A.repelling_fixed_point() Boundary point in UHP 0
>>> from sage.all import * >>> UHP = HyperbolicPlane().UHP() >>> A = UHP.get_isometry(Matrix(Integer(2),[Integer(4),Integer(0),Integer(0),Integer(1)/Integer(4)])) >>> A.repelling_fixed_point() Boundary point in UHP 0
- to_model(other)[source]#
Convert the current object to image in another model.
INPUT:
other
– (a string representing) the image model
EXAMPLES:
sage: H = HyperbolicPlane() sage: UHP = H.UHP() sage: PD = H.PD() sage: KM = H.KM() sage: HM = H.HM() sage: A = UHP.get_isometry(identity_matrix(2)) sage: A.to_model(HM) Isometry in HM [1 0 0] [0 1 0] [0 0 1] sage: A.to_model('HM') Isometry in HM [1 0 0] [0 1 0] [0 0 1] sage: A = PD.get_isometry(matrix([[I, 0], [0, -I]])) sage: A.to_model(UHP) Isometry in UHP [ 0 1] [-1 0] sage: A.to_model(HM) Isometry in HM [-1 0 0] [ 0 -1 0] [ 0 0 1] sage: A.to_model(KM) Isometry in KM [-1 0 0] [ 0 -1 0] [ 0 0 1] sage: A = HM.get_isometry(diagonal_matrix([-1, -1, 1])) sage: A.to_model('UHP') Isometry in UHP [ 0 -1] [ 1 0] sage: A.to_model('PD') Isometry in PD [-I 0] [ 0 I] sage: A.to_model('KM') Isometry in KM [-1 0 0] [ 0 -1 0] [ 0 0 1]
>>> from sage.all import * >>> H = HyperbolicPlane() >>> UHP = H.UHP() >>> PD = H.PD() >>> KM = H.KM() >>> HM = H.HM() >>> A = UHP.get_isometry(identity_matrix(Integer(2))) >>> A.to_model(HM) Isometry in HM [1 0 0] [0 1 0] [0 0 1] >>> A.to_model('HM') Isometry in HM [1 0 0] [0 1 0] [0 0 1] >>> A = PD.get_isometry(matrix([[I, Integer(0)], [Integer(0), -I]])) >>> A.to_model(UHP) Isometry in UHP [ 0 1] [-1 0] >>> A.to_model(HM) Isometry in HM [-1 0 0] [ 0 -1 0] [ 0 0 1] >>> A.to_model(KM) Isometry in KM [-1 0 0] [ 0 -1 0] [ 0 0 1] >>> A = HM.get_isometry(diagonal_matrix([-Integer(1), -Integer(1), Integer(1)])) >>> A.to_model('UHP') Isometry in UHP [ 0 -1] [ 1 0] >>> A.to_model('PD') Isometry in PD [-I 0] [ 0 I] >>> A.to_model('KM') Isometry in KM [-1 0 0] [ 0 -1 0] [ 0 0 1]
- translation_length()[source]#
For hyperbolic elements, return the translation length; otherwise, raise a
ValueError
.EXAMPLES:
sage: UHP = HyperbolicPlane().UHP() sage: H = UHP.get_isometry(matrix(2,[2,0,0,1/2])) sage: H.translation_length() 2*arccosh(5/4)
>>> from sage.all import * >>> UHP = HyperbolicPlane().UHP() >>> H = UHP.get_isometry(matrix(Integer(2),[Integer(2),Integer(0),Integer(0),Integer(1)/Integer(2)])) >>> H.translation_length() 2*arccosh(5/4)
sage: f_1 = UHP.get_point(-1) sage: f_2 = UHP.get_point(1) sage: H = UHP.isometry_from_fixed_points(f_1, f_2) sage: p = UHP.get_point(exp(i*7*pi/8)) sage: bool((p.dist(H*p) - H.translation_length()) < 10**-9) True
>>> from sage.all import * >>> f_1 = UHP.get_point(-Integer(1)) >>> f_2 = UHP.get_point(Integer(1)) >>> H = UHP.isometry_from_fixed_points(f_1, f_2) >>> p = UHP.get_point(exp(i*Integer(7)*pi/Integer(8))) >>> bool((p.dist(H*p) - H.translation_length()) < Integer(10)**-Integer(9)) True
- class sage.geometry.hyperbolic_space.hyperbolic_isometry.HyperbolicIsometryKM(model, A, check=True)[source]#
Bases:
HyperbolicIsometry
Create a hyperbolic isometry in the KM model.
INPUT:
a matrix in \(SO(2,1)\)
EXAMPLES:
sage: HyperbolicPlane().KM().get_isometry(identity_matrix(3)) Isometry in KM [1 0 0] [0 1 0] [0 0 1]
>>> from sage.all import * >>> HyperbolicPlane().KM().get_isometry(identity_matrix(Integer(3))) Isometry in KM [1 0 0] [0 1 0] [0 0 1]
- class sage.geometry.hyperbolic_space.hyperbolic_isometry.HyperbolicIsometryPD(model, A, check=True)[source]#
Bases:
HyperbolicIsometry
Create a hyperbolic isometry in the PD model.
INPUT:
a matrix in \(PU(1,1)\)
EXAMPLES:
sage: HyperbolicPlane().PD().get_isometry(identity_matrix(2)) Isometry in PD [1 0] [0 1]
>>> from sage.all import * >>> HyperbolicPlane().PD().get_isometry(identity_matrix(Integer(2))) Isometry in PD [1 0] [0 1]
- preserves_orientation()[source]#
Return
True
ifself
preserves orientation andFalse
otherwise.EXAMPLES:
sage: PD = HyperbolicPlane().PD() sage: PD.get_isometry(matrix([[-I, 0], [0, I]])).preserves_orientation() True sage: PD.get_isometry(matrix([[0, I], [I, 0]])).preserves_orientation() False
>>> from sage.all import * >>> PD = HyperbolicPlane().PD() >>> PD.get_isometry(matrix([[-I, Integer(0)], [Integer(0), I]])).preserves_orientation() True >>> PD.get_isometry(matrix([[Integer(0), I], [I, Integer(0)]])).preserves_orientation() False
- class sage.geometry.hyperbolic_space.hyperbolic_isometry.HyperbolicIsometryUHP(model, A, check=True)[source]#
Bases:
HyperbolicIsometry
Create a hyperbolic isometry in the UHP model.
INPUT:
a matrix in \(GL(2, \RR)\)
EXAMPLES:
sage: HyperbolicPlane().UHP().get_isometry(identity_matrix(2)) Isometry in UHP [1 0] [0 1]
>>> from sage.all import * >>> HyperbolicPlane().UHP().get_isometry(identity_matrix(Integer(2))) Isometry in UHP [1 0] [0 1]
- attracting_fixed_point()[source]#
Return the attracting fixed point.
Otherwise, this raises a
ValueError
.OUTPUT:
a hyperbolic point
EXAMPLES:
sage: UHP = HyperbolicPlane().UHP() sage: A = matrix(2,[4,0,0,1/4]) sage: UHP.get_isometry(A).attracting_fixed_point() Boundary point in UHP +Infinity
>>> from sage.all import * >>> UHP = HyperbolicPlane().UHP() >>> A = matrix(Integer(2),[Integer(4),Integer(0),Integer(0),Integer(1)/Integer(4)]) >>> UHP.get_isometry(A).attracting_fixed_point() Boundary point in UHP +Infinity
- classification()[source]#
Classify the hyperbolic isometry as elliptic, parabolic, or hyperbolic.
A hyperbolic isometry fixes two points on the boundary of hyperbolic space, a parabolic isometry fixes one point on the boundary of hyperbolic space, and an elliptic isometry fixes no points.
EXAMPLES:
sage: UHP = HyperbolicPlane().UHP() sage: UHP.get_isometry(identity_matrix(2)).classification() 'identity' sage: UHP.get_isometry(4*identity_matrix(2)).classification() 'identity' sage: UHP.get_isometry(matrix(2,[2,0,0,1/2])).classification() 'hyperbolic' sage: UHP.get_isometry(matrix(2, [0, 3, -1/3, 6])).classification() 'hyperbolic' sage: UHP.get_isometry(matrix(2,[1,1,0,1])).classification() 'parabolic' sage: UHP.get_isometry(matrix(2,[-1,0,0,1])).classification() 'reflection'
>>> from sage.all import * >>> UHP = HyperbolicPlane().UHP() >>> UHP.get_isometry(identity_matrix(Integer(2))).classification() 'identity' >>> UHP.get_isometry(Integer(4)*identity_matrix(Integer(2))).classification() 'identity' >>> UHP.get_isometry(matrix(Integer(2),[Integer(2),Integer(0),Integer(0),Integer(1)/Integer(2)])).classification() 'hyperbolic' >>> UHP.get_isometry(matrix(Integer(2), [Integer(0), Integer(3), -Integer(1)/Integer(3), Integer(6)])).classification() 'hyperbolic' >>> UHP.get_isometry(matrix(Integer(2),[Integer(1),Integer(1),Integer(0),Integer(1)])).classification() 'parabolic' >>> UHP.get_isometry(matrix(Integer(2),[-Integer(1),Integer(0),Integer(0),Integer(1)])).classification() 'reflection'
- fixed_point_set()[source]#
Return a list or geodesic containing the fixed point set of orientation-preserving isometries.
OUTPUT:
list of hyperbolic points or a hyperbolic geodesic
EXAMPLES:
sage: UHP = HyperbolicPlane().UHP() sage: H = UHP.get_isometry(matrix(2, [-2/3,-1/3,-1/3,-2/3])) sage: g = H.fixed_point_set(); g Geodesic in UHP from -1 to 1 sage: H(g.start()) == g.start() True sage: H(g.end()) == g.end() True sage: A = UHP.get_isometry(matrix(2,[0,1,1,0])) sage: A.preserves_orientation() False sage: A.fixed_point_set() Geodesic in UHP from 1 to -1
>>> from sage.all import * >>> UHP = HyperbolicPlane().UHP() >>> H = UHP.get_isometry(matrix(Integer(2), [-Integer(2)/Integer(3),-Integer(1)/Integer(3),-Integer(1)/Integer(3),-Integer(2)/Integer(3)])) >>> g = H.fixed_point_set(); g Geodesic in UHP from -1 to 1 >>> H(g.start()) == g.start() True >>> H(g.end()) == g.end() True >>> A = UHP.get_isometry(matrix(Integer(2),[Integer(0),Integer(1),Integer(1),Integer(0)])) >>> A.preserves_orientation() False >>> A.fixed_point_set() Geodesic in UHP from 1 to -1
sage: B = UHP.get_isometry(identity_matrix(2)) sage: B.fixed_point_set() Traceback (most recent call last): ... ValueError: the identity transformation fixes the entire hyperbolic plane
>>> from sage.all import * >>> B = UHP.get_isometry(identity_matrix(Integer(2))) >>> B.fixed_point_set() Traceback (most recent call last): ... ValueError: the identity transformation fixes the entire hyperbolic plane
- preserves_orientation()[source]#
Return
True
ifself
is orientation-preserving andFalse
otherwise.EXAMPLES:
sage: UHP = HyperbolicPlane().UHP() sage: A = identity_matrix(2) sage: UHP.get_isometry(A).preserves_orientation() True sage: B = matrix(2,[0,1,1,0]) sage: UHP.get_isometry(B).preserves_orientation() False
>>> from sage.all import * >>> UHP = HyperbolicPlane().UHP() >>> A = identity_matrix(Integer(2)) >>> UHP.get_isometry(A).preserves_orientation() True >>> B = matrix(Integer(2),[Integer(0),Integer(1),Integer(1),Integer(0)]) >>> UHP.get_isometry(B).preserves_orientation() False
- repelling_fixed_point()[source]#
Return the repelling fixed point.
Otherwise, this raises a
ValueError
.OUTPUT:
a hyperbolic point
EXAMPLES:
sage: UHP = HyperbolicPlane().UHP() sage: A = matrix(2,[4,0,0,1/4]) sage: UHP.get_isometry(A).repelling_fixed_point() Boundary point in UHP 0
>>> from sage.all import * >>> UHP = HyperbolicPlane().UHP() >>> A = matrix(Integer(2),[Integer(4),Integer(0),Integer(0),Integer(1)/Integer(4)]) >>> UHP.get_isometry(A).repelling_fixed_point() Boundary point in UHP 0
- translation_length()[source]#
For hyperbolic elements, return the translation length; otherwise, raise a
ValueError
.EXAMPLES:
sage: UHP = HyperbolicPlane().UHP() sage: UHP.get_isometry(matrix(2,[2,0,0,1/2])).translation_length() 2*arccosh(5/4)
>>> from sage.all import * >>> UHP = HyperbolicPlane().UHP() >>> UHP.get_isometry(matrix(Integer(2),[Integer(2),Integer(0),Integer(0),Integer(1)/Integer(2)])).translation_length() 2*arccosh(5/4)
sage: H = UHP.isometry_from_fixed_points(-1,1) sage: p = UHP.get_point(exp(i*7*pi/8)) sage: Hp = H(p) sage: bool((UHP.dist(p, Hp) - H.translation_length()) < 10**-9) True
>>> from sage.all import * >>> H = UHP.isometry_from_fixed_points(-Integer(1),Integer(1)) >>> p = UHP.get_point(exp(i*Integer(7)*pi/Integer(8))) >>> Hp = H(p) >>> bool((UHP.dist(p, Hp) - H.translation_length()) < Integer(10)**-Integer(9)) True
- sage.geometry.hyperbolic_space.hyperbolic_isometry.moebius_transform(A, z)[source]#
Given a matrix
A
in \(GL(2, \CC)\) and a pointz
in the complex plane return the Möbius transformation action ofA
onz
.INPUT:
A
– a \(2 \times 2\) invertible matrix over the complex numbersz
– a complex number or infinity
OUTPUT:
a complex number or infinity
EXAMPLES:
sage: from sage.geometry.hyperbolic_space.hyperbolic_model import moebius_transform sage: moebius_transform(matrix(2,[1,2,3,4]),2 + I) -2/109*I + 43/109 sage: y = var('y') sage: moebius_transform(matrix(2,[1,0,0,1]),x + I*y) x + I*y
>>> from sage.all import * >>> from sage.geometry.hyperbolic_space.hyperbolic_model import moebius_transform >>> moebius_transform(matrix(Integer(2),[Integer(1),Integer(2),Integer(3),Integer(4)]),Integer(2) + I) -2/109*I + 43/109 >>> y = var('y') >>> moebius_transform(matrix(Integer(2),[Integer(1),Integer(0),Integer(0),Integer(1)]),x + I*y) x + I*y
The matrix must be square and \(2 \times 2\):
sage: moebius_transform(matrix([[3,1,2],[1,2,5]]),I) Traceback (most recent call last): ... TypeError: A must be an invertible 2x2 matrix over the complex numbers or a symbolic ring sage: moebius_transform(identity_matrix(3),I) Traceback (most recent call last): ... TypeError: A must be an invertible 2x2 matrix over the complex numbers or a symbolic ring
>>> from sage.all import * >>> moebius_transform(matrix([[Integer(3),Integer(1),Integer(2)],[Integer(1),Integer(2),Integer(5)]]),I) Traceback (most recent call last): ... TypeError: A must be an invertible 2x2 matrix over the complex numbers or a symbolic ring >>> moebius_transform(identity_matrix(Integer(3)),I) Traceback (most recent call last): ... TypeError: A must be an invertible 2x2 matrix over the complex numbers or a symbolic ring
The matrix can be symbolic or can be a matrix over the real or complex numbers, but must be provably invertible:
sage: a,b,c,d = var('a,b,c,d') sage: moebius_transform(matrix(2,[a,b,c,d]),I) (I*a + b)/(I*c + d) sage: moebius_transform(matrix(2,[1,b,c,b*c+1]),I) (b + I)/(b*c + I*c + 1) sage: moebius_transform(matrix(2,[0,0,0,0]),I) Traceback (most recent call last): ... TypeError: A must be an invertible 2x2 matrix over the complex numbers or a symbolic ring
>>> from sage.all import * >>> a,b,c,d = var('a,b,c,d') >>> moebius_transform(matrix(Integer(2),[a,b,c,d]),I) (I*a + b)/(I*c + d) >>> moebius_transform(matrix(Integer(2),[Integer(1),b,c,b*c+Integer(1)]),I) (b + I)/(b*c + I*c + 1) >>> moebius_transform(matrix(Integer(2),[Integer(0),Integer(0),Integer(0),Integer(0)]),I) Traceback (most recent call last): ... TypeError: A must be an invertible 2x2 matrix over the complex numbers or a symbolic ring