Hecke triangle group elements#
AUTHORS:
Jonas Jermann (2014): initial version
- class sage.modular.modform_hecketriangle.hecke_triangle_group_element.HeckeTriangleGroupElement(parent, M, check=True, **kwargs)#
Bases:
MatrixGroupElement_generic
Elements of HeckeTriangleGroup.
- a()#
Return the upper left entry of
self
.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: U = HeckeTriangleGroup(n=7).U() sage: U.a() lam sage: U.a().parent() Maximal Order in Number Field in lam with defining polynomial x^3 - x^2 - 2*x + 1 with lam = 1.801937735804839?
- acton(tau)#
Return the image of
tau
under the action ofself
by linear fractional transformations or by conjugation in casetau
is an element of the parent ofself
.It is possible to act on points of
HyperbolicPlane()
.Note
There is a 1-1 correspondence between hyperbolic fixed points and the corresponding primitive element in the stabilizer. The action in the two cases above is compatible with this correspondence.
INPUT:
tau
– Either an element ofself
or anyelement to which a linear fractional transformation can be applied in the usual way.
In particular
infinity
is a possible argument and a possible return value.As mentioned it is also possible to use points of
HyperbolicPlane()
.
EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(5) sage: G.S().acton(SR(1 + i/2)) 2/5*I - 4/5 sage: G.S().acton(SR(1 + i/2)).parent() Symbolic Ring sage: G.S().acton(QQbar(1 + i/2)) 2/5*I - 4/5 sage: G.S().acton(QQbar(1 + i/2)).parent() Algebraic Field sage: G.S().acton(i + exp(-2)) -1/(e^(-2) + I) sage: G.S().acton(i + exp(-2)).parent() Symbolic Ring sage: G.T().acton(infinity) == infinity True sage: G.U().acton(infinity) lam sage: G.V(2).acton(-G.lam()) == infinity True sage: G.V(2).acton(G.U()) == G.V(2)*G.U()*G.V(2).inverse() True sage: G.V(2).inverse().acton(G.U()) [ 0 -1] [ 1 lam] sage: p = HyperbolicPlane().PD().get_point(-I/2+1/8) sage: G.V(2).acton(p) Point in PD -((-(47*I + 161)*sqrt(5) - 47*I - 161)/(145*sqrt(5) + 94*I + 177) + I)/(I*(-(47*I + 161)*sqrt(5) - 47*I - 161)/(145*sqrt(5) + 94*I + 177) + 1) sage: bool(G.V(2).acton(p).to_model('UHP').coordinates() == G.V(2).acton(p.to_model('UHP').coordinates())) True sage: p = HyperbolicPlane().PD().get_point(I) sage: G.U().acton(p) Boundary point in PD 1/2*(sqrt(5) - 2*I + 1)/(-1/2*I*sqrt(5) - 1/2*I + 1) sage: G.U().acton(p).to_model('UHP') == HyperbolicPlane().UHP().get_point(G.lam()) True sage: G.U().acton(p) == HyperbolicPlane().UHP().get_point(G.lam()).to_model('PD') True
- as_hyperbolic_plane_isometry(model='UHP')#
Return
self
as an isometry ofHyperbolicPlane()
(in the upper half plane model).EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: el = HeckeTriangleGroup(7).V(4) sage: el.as_hyperbolic_plane_isometry() Isometry in UHP [lam^2 - 1 lam] [lam^2 - 1 lam^2 - 1] sage: el.as_hyperbolic_plane_isometry().parent() Set of Morphisms from Hyperbolic plane in the Upper Half Plane Model to Hyperbolic plane in the Upper Half Plane Model in Category of hyperbolic models of Hyperbolic plane sage: el.as_hyperbolic_plane_isometry("KM").parent() Set of Morphisms from Hyperbolic plane in the Klein Disk Model to Hyperbolic plane in the Klein Disk Model in Category of hyperbolic models of Hyperbolic plane
- b()#
Return the upper right entry of
self
.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: U = HeckeTriangleGroup(n=7).U() sage: U.b() -1 sage: U.b().parent() Maximal Order in Number Field in lam with defining polynomial x^3 - x^2 - 2*x + 1 with lam = 1.801937735804839?
- block_decomposition()#
Return a tuple
(L, R, sgn)
such thatself = sgn * R.acton(prod(L)) = sgn * R*prod(L)*R.inverse()
.In the parabolic and hyperbolic case the tuple entries in
L
are powers of basic block matrices:V(j) = U^(j-1)*T = self.parent().V(j)
for1 <= j <= n-1
. In the elliptic case the tuple entries are eitherS
orU
.This decomposition data is (also) described by
_block_decomposition_data()
.Warning: The case
n=infinity
is not verified at all and probably wrong!EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: G.element_repr_method("basic") sage: G.T().block_decomposition() ((T,), T^(-1), 1) sage: G.V(2).acton(G.T(-3)).block_decomposition() ((-S*T^(-3)*S,), T, 1) sage: (-G.V(2)^2).block_decomposition() ((T*S*T^2*S*T,), T*S*T, -1) sage: el = (-G.V(2)*G.V(6)*G.V(3)*G.V(2)*G.V(6)*G.V(3)) sage: el.block_decomposition() ((-S*T^(-1)*S, T*S*T*S*T, T*S*T, -S*T^(-1)*S, T*S*T*S*T, T*S*T), T*S*T, -1) sage: (G.U()^4*G.S()*G.V(2)).acton(el).block_decomposition() ((T*S*T, -S*T^(-1)*S, T*S*T*S*T, T*S*T, -S*T^(-1)*S, T*S*T*S*T), T*S*T*S*T*S*T^2*S*T, -1) sage: (G.V(1)^5*G.V(2)*G.V(3)^3).block_decomposition() ((T*S*T*S*T^2*S*T*S*T^2*S*T*S*T, T^5, T*S*T), T^6*S*T, 1) sage: G.element_repr_method("default") sage: (-G.I()).block_decomposition() ( ([1 0] [1 0] [-1 0] [0 1],), [0 1], [ 0 -1] ) sage: G.U().block_decomposition() ( ([lam -1] [1 0] [1 0] [ 1 0],), [0 1], [0 1] ) sage: (-G.S()).block_decomposition() ( ([ 0 -1] [-1 0] [-1 0] [ 1 0],), [ 0 -1], [ 0 -1] ) sage: (G.V(2)*G.V(3)).acton(G.U()^6).block_decomposition() ( ([ 0 1] [-2*lam^2 - 2*lam + 2 -2*lam^2 - 2*lam + 1] [-1 0] [ -1 lam],), [ -2*lam^2 + 1 -2*lam^2 - lam + 2], [ 0 -1] ) sage: (G.U()^(-6)).block_decomposition() ( ([lam -1] [1 0] [-1 0] [ 1 0],), [0 1], [ 0 -1] ) sage: G = HeckeTriangleGroup(n=8) sage: (G.U()^4).block_decomposition() ( ([ lam^2 - 1 -lam^3 + 2*lam] [1 0] [1 0] [ lam^3 - 2*lam -lam^2 + 1],), [0 1], [0 1] ) sage: (G.U()^(-4)).block_decomposition() ( ([ lam^2 - 1 -lam^3 + 2*lam] [1 0] [-1 0] [ lam^3 - 2*lam -lam^2 + 1],), [0 1], [ 0 -1] )
- block_length(primitive=False)#
Return the block length of
self
. The block length is given by the number of factors used for the decomposition of the conjugacy representative ofself
described inprimitive_representative()
. In particular the block length is invariant under conjugation.The definition is mostly used for parabolic or hyperbolic elements: In particular it gives a lower bound for the (absolute value of) the trace and the discriminant for primitive hyperbolic elements. Namely
abs(trace) >= lambda * block_length
anddiscriminant >= block_length^2 * lambda^2 - 4
.Warning: The case
n=infinity
is not verified at all and probably wrong!INPUT:
primitive
– IfTrue
then the conjugacyrepresentative of the primitive part is used instead, default:
False
.
OUTPUT:
An integer. For hyperbolic elements a non-negative integer. For parabolic elements a negative sign corresponds to taking the inverse. For elliptic elements a (non-trivial) integer with minimal absolute value is choosen. For +- the identity element
0
is returned.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: G.T().block_length() 1 sage: G.V(2).acton(G.T(-3)).block_length() 3 sage: G.V(2).acton(G.T(-3)).block_length(primitive=True) 1 sage: (-G.V(2)).block_length() 1 sage: el = -G.V(2)^3*G.V(6)^2*G.V(3) sage: t = el.block_length() sage: D = el.discriminant() sage: trace = el.trace() sage: (trace, D, t) (-124*lam^2 - 103*lam + 68, 65417*lam^2 + 52456*lam - 36300, 6) sage: abs(AA(trace)) >= AA(G.lam()*t) True sage: AA(D) >= AA(t^2 * G.lam() - 4) True sage: (el^3).block_length(primitive=True) == t True sage: el = (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3)) sage: t = el.block_length() sage: D = el.discriminant() sage: trace = el.trace() sage: (trace, D, t) (-124*lam^2 - 103*lam + 68, 65417*lam^2 + 52456*lam - 36300, 6) sage: abs(AA(trace)) >= AA(G.lam()*t) True sage: AA(D) >= AA(t^2 * G.lam() - 4) True sage: (el^(-2)).block_length(primitive=True) == t True sage: el = G.V(1)^5*G.V(2)*G.V(3)^3 sage: t = el.block_length() sage: D = el.discriminant() sage: trace = el.trace() sage: (trace, D, t) (284*lam^2 + 224*lam - 156, 330768*lam^2 + 265232*lam - 183556, 9) sage: abs(AA(trace)) >= AA(G.lam()*t) True sage: AA(D) >= AA(t^2 * G.lam() - 4) True sage: (el^(-1)).block_length(primitive=True) == t True sage: (G.V(2)*G.V(3)).acton(G.U()^6).block_length() 1 sage: (G.V(2)*G.V(3)).acton(G.U()^6).block_length(primitive=True) 1 sage: (-G.I()).block_length() 0 sage: G.U().block_length() 1 sage: (-G.S()).block_length() 1
- c()#
Return the lower left entry of
self
.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: U = HeckeTriangleGroup(n=7).U() sage: U.c() 1
- conjugacy_type(ignore_sign=True, primitive=False)#
Return a unique description of the conjugacy class of
self
(by default only up to a sign).Warning: The case
n=infinity
is not verified at all and probably wrong!INPUT:
ignore_sign
– IfTrue
(default) then the conjugacyclasses are only considered up to a sign.
primitive
– IfTrue
then the conjugacy class ofthe primitive part is considered instead and the sign is ignored, default:
False
.
OUTPUT:
A unique representative for the given block data (without the conjugation matrix) among all cyclic permutations. If
ignore_sign=True
then the sign is excluded as well.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: (-G.I()).conjugacy_type() ((6, 0),) sage: G.U().acton(G.S()).conjugacy_type() (0, 1) sage: (G.U()^4).conjugacy_type() (1, -3) sage: ((G.V(2)*G.V(3)^2*G.V(2)*G.V(3))^2).conjugacy_type() ((3, 2), (2, 1), (3, 1), (2, 1), (3, 2), (2, 1), (3, 1), (2, 1)) sage: (-G.I()).conjugacy_type(ignore_sign=False) (((6, 0),), -1) sage: G.S().conjugacy_type(ignore_sign=False) ((0, 1), 1) sage: (G.U()^4).conjugacy_type(ignore_sign=False) ((1, -3), -1) sage: G.U().acton((G.V(2)*G.V(3)^2*G.V(2)*G.V(3))^2).conjugacy_type(ignore_sign=False) (((3, 2), (2, 1), (3, 1), (2, 1), (3, 2), (2, 1), (3, 1), (2, 1)), 1) sage: (-G.I()).conjugacy_type(primitive=True) ((6, 0),) sage: G.S().conjugacy_type(primitive=True) (0, 1) sage: G.V(2).acton(G.U()^4).conjugacy_type(primitive=True) (1, 1) sage: (G.V(3)^2).conjugacy_type(primitive=True) ((3, 1),) sage: G.S().acton((G.V(2)*G.V(3)^2*G.V(2)*G.V(3))^2).conjugacy_type(primitive=True) ((3, 2), (2, 1), (3, 1), (2, 1))
- continued_fraction()#
For hyperbolic and parabolic elements: Return the (negative) lambda-continued fraction expansion (lambda-CF) of the (attracting) hyperbolic fixed point of
self
.Let
r_j in Z
forj >= 0
. A finite lambda-CF is defined as:[r_0; r_1, ..., r_k] := (T^(r_0)*S* ... *T^(r_k)*S)(infinity)
, whereS
andT
are the generators ofself
. An infinite lambda-CF is defined as a corresponding limit value (k->infinity) if it exists.In this case the lambda-CF of parabolic and hyperbolic fixed points are returned which have an eventually periodic lambda-CF. The parabolic elements are exactly those with a cyclic permutation of the period
[2, 1, ..., 1]
withn-3
ones.Warning: The case
n=infinity
is not verified at all and probably wrong!OUTPUT:
A tuple
(preperiod, period)
with the preperiod and period tuples of the lambda-CF.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: G.T().continued_fraction() ((0, 1), (1, 1, 1, 1, 2)) sage: G.V(2).acton(G.T(-3)).continued_fraction() ((), (2, 1, 1, 1, 1)) sage: (-G.V(2)).continued_fraction() ((1,), (2,)) sage: (-G.V(2)^3*G.V(6)^2*G.V(3)).continued_fraction() ((1,), (2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 2)) sage: (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3)).continued_fraction() ((1, 1, 1, 2), (2, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1)) sage: (G.V(1)^5*G.V(2)*G.V(3)^3).continued_fraction() ((6,), (2, 1, 2, 1, 2, 1, 7)) sage: G = HeckeTriangleGroup(n=8) sage: G.T().continued_fraction() ((0, 1), (1, 1, 1, 1, 1, 2)) sage: G.V(2).acton(G.T(-3)).continued_fraction() ((), (2, 1, 1, 1, 1, 1)) sage: (-G.V(2)).continued_fraction() ((1,), (2,)) sage: (-G.V(2)^3*G.V(6)^2*G.V(3)).continued_fraction() ((1,), (2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 2)) sage: (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3)).continued_fraction() ((1, 1, 1, 2), (2, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1)) sage: (G.V(1)^5*G.V(2)*G.V(3)^3).continued_fraction() ((6,), (2, 1, 2, 1, 2, 1, 7)) sage: (G.V(2)^3*G.V(5)*G.V(1)*G.V(6)^2*G.V(4)).continued_fraction() ((1,), (2, 2, 2, 1, 1, 1, 3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 2))
- d()#
Return the lower right of
self
.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: U = HeckeTriangleGroup(n=7).U() sage: U.d() 0
- discriminant()#
Return the discriminant of
self
which corresponds to the discriminant of the corresponding quadratic form ofself
.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: G.V(3).discriminant() 4*lam^2 + 4*lam - 4 sage: AA(G.V(3).discriminant()) 16.19566935808922?
- fixed_points(embedded=False, order='default')#
Return a pair of (mutually conjugate) fixed points of
self
in a possible quadratic extension of the base field.INPUT:
embedded
– IfTrue
the fixed points are embedded intoAlgebraicRealField
resp.AlgebraicField
. Default:False
.
order
– Iforder="none"
the fixed points are choosenand ordered according to a fixed formula.
If
order="sign"
the fixed points are always ordered according to the sign in front of the square root.If
order="default"
(default) then in case the fixed points are hyperbolic they are ordered according to the sign of the trace ofself
instead, such that the attracting fixed point comes first.If
order="trace"
the fixed points are always ordered according to the sign of the trace ofself
. If the trace is zero they are ordered by the sign in front of the square root. In particular the fixed_points in this case remain the same for-self
.
OUTPUT:
If
embedded=True
an element of eitherAlgebraicRealField
orAlgebraicField
is returned. Otherwise an element of a relative field extension over the base field of (the parent of)self
is returned.Warning: Relative field extensions don’t support default embeddings. So the correct embedding (which is the positive resp. imaginary positive one) has to be choosen.
EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=infinity) sage: (-G.T(-4)).fixed_points() (+Infinity, +Infinity) sage: (-G.S()).fixed_points() (1/2*e, -1/2*e) sage: p = (-G.S()).fixed_points(embedded=True)[0] sage: p I sage: (-G.S()).acton(p) == p True sage: (-G.V(2)).fixed_points() (1/2*e, -1/2*e) sage: (-G.V(2)).fixed_points() == G.V(2).fixed_points() True sage: p = (-G.V(2)).fixed_points(embedded=True)[1] sage: p -1.732050807568878? sage: (-G.V(2)).acton(p) == p True sage: G = HeckeTriangleGroup(n=7) sage: (-G.S()).fixed_points() (1/2*e, -1/2*e) sage: p = (-G.S()).fixed_points(embedded=True)[1] sage: p -I sage: (-G.S()).acton(p) == p True sage: (G.U()^4).fixed_points() ((1/2*lam^2 - 1/2*lam - 1/2)*e + 1/2*lam, (-1/2*lam^2 + 1/2*lam + 1/2)*e + 1/2*lam) sage: pts = (G.U()^4).fixed_points(order="trace") sage: (G.U()^4).fixed_points() == [pts[1], pts[0]] False sage: (G.U()^4).fixed_points(order="trace") == (-G.U()^4).fixed_points(order="trace") True sage: (G.U()^4).fixed_points() == (G.U()^4).fixed_points(order="none") True sage: (-G.U()^4).fixed_points() == (G.U()^4).fixed_points() True sage: (-G.U()^4).fixed_points(order="none") == pts True sage: p = (G.U()^4).fixed_points(embedded=True)[1] sage: p 0.9009688679024191? - 0.4338837391175581?*I sage: (G.U()^4).acton(p) == p True sage: (-G.V(5)).fixed_points() ((1/2*lam^2 - 1/2*lam - 1/2)*e, (-1/2*lam^2 + 1/2*lam + 1/2)*e) sage: (-G.V(5)).fixed_points() == G.V(5).fixed_points() True sage: p = (-G.V(5)).fixed_points(embedded=True)[0] sage: p 0.6671145837954892? sage: (-G.V(5)).acton(p) == p True
- is_elliptic()#
Return whether
self
is an elliptic matrix.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: [ G.V(k).is_elliptic() for k in range(1,8) ] [False, False, False, False, False, False, True] sage: G.U().is_elliptic() True
- is_hecke_symmetric()#
Return whether the conjugacy class of the primitive part of
self
, denoted by[gamma]
is \(Hecke-symmetric\): I.e. if[gamma] == [gamma^(-1)]
.This is equivalent to
self.simple_fixed_point_set()
being equal with it’s \(Hecke-conjugated\) set (where each fixed point is replaced by the other (\(Hecke-conjugated\)) fixed point.It is also equivalent to
[Q] == [-Q]
for the corresponding hyperbolic binary quadratic formQ
.The method assumes that
self
is hyperbolic.Warning
The case
n=infinity
is not verified at all and probably wrong!EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=5) sage: el = G.V(2) sage: el.is_hecke_symmetric() False sage: (el.simple_fixed_point_set(), el.inverse().simple_fixed_point_set()) ({1/2*e, (-1/2*lam + 1/2)*e}, {-1/2*e, (1/2*lam - 1/2)*e}) sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6) sage: el.is_hecke_symmetric() False sage: el.simple_fixed_point_set() == el.inverse().simple_fixed_point_set() False sage: el = G.V(2)*G.V(3) sage: el.is_hecke_symmetric() True sage: sorted(el.simple_fixed_point_set(), key=str) [(-lam + 3/2)*e + 1/2*lam - 1, (-lam + 3/2)*e - 1/2*lam + 1, (lam - 3/2)*e + 1/2*lam - 1, (lam - 3/2)*e - 1/2*lam + 1] sage: el.simple_fixed_point_set() == el.inverse().simple_fixed_point_set() True
- is_hyperbolic()#
Return whether
self
is a hyperbolic matrix.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: [ G.V(k).is_hyperbolic() for k in range(1,8) ] [False, True, True, True, True, False, False] sage: G.U().is_hyperbolic() False
- is_identity()#
Return whether
self
is the identity or minus the identity.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: [ G.V(k).is_identity() for k in range(1,8) ] [False, False, False, False, False, False, False] sage: G.U().is_identity() False
- is_parabolic(exclude_one=False)#
Return whether
self
is a parabolic matrix.If
exclude_one
is set, then +- the identity element is not considered parabolic.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: [ G.V(k).is_parabolic() for k in range(1,8) ] [True, False, False, False, False, True, False] sage: G.U().is_parabolic() False sage: G.V(6).is_parabolic(exclude_one=True) True sage: G.V(7).is_parabolic(exclude_one=True) False
- is_primitive()#
Returns whether
self
is primitive. We call an element primitive if (up to a sign and taking inverses) it generates the full stabilizer subgroup of the corresponding fixed point. In the non-elliptic case this means that primitive elements cannot be written as a \(non-trivial\) power of another element.The notion is mostly used for hyperbolic and parabolic elements.
Warning: The case
n=infinity
is not verified at all and probably wrong!EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: G.V(2).acton(G.T(-1)).is_primitive() True sage: G.T(3).is_primitive() False sage: (-G.V(2)^2).is_primitive() False sage: (G.V(1)^5*G.V(2)*G.V(3)^3).is_primitive() True sage: (-G.I()).is_primitive() True sage: (-G.U()).is_primitive() True sage: (-G.S()).is_primitive() True sage: (G.U()^6).is_primitive() True sage: G = HeckeTriangleGroup(n=8) sage: (G.U()^2).is_primitive() False sage: (G.U()^(-4)).is_primitive() False sage: (G.U()^(-3)).is_primitive() True
- is_reduced(require_primitive=True, require_hyperbolic=True)#
Returns whether
self
is reduced. We call an element reduced if the associated lambda-CF is purely periodic.I.e. (in the hyperbolic case) if the associated hyperbolic fixed point (resp. the associated hyperbolic binary quadratic form) is reduced.
Note that if
self
is reduced then the element corresponding to the cyclic permutation of the lambda-CF (which is conjugate to the original element) is again reduced. In particular the reduced elements in the conjugacy class ofself
form a finite cycle.Elliptic elements and +- identity are not considered reduced.
Warning: The case
n=infinity
is not verified at all and probably wrong!INPUT:
require_primitive
– IfTrue
(default) then non-primitive elementsare not considered reduced.
require_hyperbolic
– IfTrue
(default) then non-hyperbolic elementsare not considered reduced.
EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: G.I().is_reduced(require_hyperbolic=False) False sage: G.U().reduce().is_reduced(require_hyperbolic=False) False sage: G.T().reduce().is_reduced() False sage: G.T().reduce().is_reduced(require_hyperbolic=False) True sage: (G.V(5)^2).reduce(primitive=False).is_reduced() False sage: (G.V(5)^2).reduce(primitive=False).is_reduced(require_primitive=False) True sage: G.V(5).reduce().is_reduced() True sage: (-G.V(2)).reduce().is_reduced() True sage: (-G.V(2)^3*G.V(6)^2*G.V(3)).reduce().is_reduced() True sage: (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3)).reduce().is_reduced() True
- is_reflection()#
Return whether
self
is the usual reflection on the unit circle.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: (-HeckeTriangleGroup(n=7).S()).is_reflection() True sage: HeckeTriangleGroup(n=7).U().is_reflection() False
- is_simple()#
Return whether
self
is simple. We call an element simple if it is hyperbolic, primitive, has positive sign and if the associated hyperbolic fixed points satisfy:alpha' < 0 < alpha
wherealpha
is the attracting fixed point for the element.I.e. if the associated hyperbolic fixed point (resp. the associated hyperbolic binary quadratic form) is simple.
There are only finitely many simple elements for a given discriminant. They can be used to provide explicit descriptions of rational period functions.
Warning: The case
n=infinity
is not verified at all and probably wrong!EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=5) sage: el = G.V(2) sage: el.is_simple() True sage: R = el.simple_elements() sage: [v.is_simple() for v in R] [True] sage: (fp1, fp2) = R[0].fixed_points(embedded=True) sage: (fp1, fp2) (1.272019649514069?, -1.272019649514069?) sage: fp2 < 0 < fp1 True sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6) sage: el.is_simple() False sage: R = el.simple_elements() sage: [v.is_simple() for v in R] [True, True] sage: (fp1, fp2) = R[1].fixed_points(embedded=True) sage: fp2 < 0 < fp1 True sage: el = G.V(1)^2*G.V(2)*G.V(4) sage: el.is_simple() True sage: R = el.simple_elements() sage: el in R True sage: [v.is_simple() for v in R] [True, True, True, True] sage: (fp1, fp2) = R[2].fixed_points(embedded=True) sage: fp2 < 0 < fp1 True
- is_translation(exclude_one=False)#
Return whether
self
is a translation. Ifexclude_one = True
, then the identity map is not considered as a translation.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: (-HeckeTriangleGroup(n=7).T(-4)).is_translation() True sage: (-HeckeTriangleGroup(n=7).I()).is_translation() True sage: (-HeckeTriangleGroup(n=7).I()).is_translation(exclude_one=True) False
- linking_number()#
Let
g
denote a holomorphic primitive ofE2
in the sense:lambda/(2*pi*i) d/dz g = E2
. Letgamma=self
and letM_gamma(z)
beLog((c*z+d) * sgn(a+d))
ifc, a+d > 0
, resp.Log((c*z+d) / i*sgn(c))
ifa+d = 0, c!=0
, resp.0
ifc=0
. Letk=4 * n / (n-2)
, then:g(gamma.acton(z) - g(z) - k*M_gamma(z)
is equal to2*pi*i / (n-2) * self.linking_number()
.In particular it is independent of
z
and a conjugacy invariant.If
self
is hyperbolic then in the classical casen=3
this is the linking number of the closed geodesic (corresponding toself
) with the trefoil knot.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms sage: def E2_primitive(z, n=3, prec=10, num_prec=53): ....: G = HeckeTriangleGroup(n=n) ....: MF = QuasiModularForms(group=G, k=2, ep=-1) ....: q = MF.get_q(prec=prec) ....: int_series = integrate((MF.E2().q_expansion(prec=prec) - 1) / q) ....: t_const = (2*pi*i/G.lam()).n(num_prec) ....: d = MF.get_d(fix_d=True, d_num_prec=num_prec) ....: q = exp(t_const * z) ....: return t_const*z + sum([(int_series.coefficients()[m]).subs(d=d) * q**int_series.exponents()[m] for m in range(len(int_series.coefficients()))]) sage: def M(gamma, z, num_prec=53): ....: a = ComplexField(num_prec)(gamma.a()) ....: b = ComplexField(num_prec)(gamma.b()) ....: c = ComplexField(num_prec)(gamma.c()) ....: d = ComplexField(num_prec)(gamma.d()) ....: if c == 0: ....: return 0 ....: elif a + d == 0: ....: return log(-i.n(num_prec)*(c*z + d)*sign(c)) ....: else: ....: return log((c*z+d)*sign(a+d)) sage: def num_linking_number(A, z, n=3, prec=10, num_prec=53): ....: z = z.n(num_prec) ....: k = 4 * n / (n - 2) ....: return (n-2) / (2*pi*i).n(num_prec) * (E2_primitive(A.acton(z), n=n, prec=prec, num_prec=num_prec) - E2_primitive(z, n=n, prec=prec, num_prec=num_prec) - k*M(A, z, num_prec=num_prec)) sage: G = HeckeTriangleGroup(8) sage: z = i sage: for A in [G.S(), G.T(), G.U(), G.U()^(G.n()//2), G.U()^(-3)]: ....: print("A={}: ".format(A.string_repr("conj"))) ....: num_linking_number(A, z, G.n()) ....: A.linking_number() A=[S]: 0.000000000000... 0 A=[V(1)]: 6.000000000000... 6 A=[U]: -2.00000000000... -2 A=[U^4]: 0.596987639289... + 0.926018962976...*I 0 A=[U^(-3)]: 5.40301236071... + 0.926018962976...*I 6 sage: z = ComplexField(1000)(- 2.3 + 3.1*i) sage: B = G.I() sage: for A in [G.S(), G.T(), G.U(), G.U()^(G.n()//2), G.U()^(-3)]: ....: print("A={}: ".format(A.string_repr("conj"))) ....: num_linking_number(B.acton(A), z, G.n(), prec=100, num_prec=1000).n(53) ....: B.acton(A).linking_number() A=[S]: 6.63923483989...e-31 + 2.45195568651...e-30*I 0 A=[V(1)]: 6.000000000000... 6 A=[U]: -2.00000000000... + 2.45195568651...e-30*I -2 A=[U^4]: 0.00772492873864... + 0.00668936643212...*I 0 A=[U^(-3)]: 5.99730551444... + 0.000847636355069...*I 6 sage: z = ComplexField(5000)(- 2.3 + 3.1*i) sage: B = G.U() sage: for A in [G.S(), G.T(), G.U(), G.U()^(G.n()//2), G.U()^(-3)]: # long time ....: print("A={}: ".format(A.string_repr("conj"))) ....: num_linking_number(B.acton(A), z, G.n(), prec=200, num_prec=5000).n(53) ....: B.acton(A).linking_number() A=[S]: -7.90944791339...e-34 - 9.38956758807...e-34*I 0 A=[V(1)]: 5.99999997397... - 5.96520311160...e-8*I 6 A=[U]: -2.00000000000... - 1.33113963568...e-61*I -2 A=[U^4]: -2.32704571946...e-6 + 5.91899385948...e-7*I 0 A=[U^(-3)]: 6.00000032148... - 1.82676936467...e-7*I 6 sage: A = G.V(2)*G.V(3) sage: B = G.I() sage: num_linking_number(B.acton(A), z, G.n(), prec=200, num_prec=5000).n(53) # long time 6.00498424588... - 0.00702329345176...*I sage: A.linking_number() 6 The numerical properties for anything larger are basically too bad to make nice further tests...
- primitive_part(method='cf')#
Return the primitive part of
self
. I.e. a group elementA
with non-negative trace such thatself = sign * A^power
, wheresign = self.sign()
is +- the identity (to correct the sign) andpower = self.primitive_power()
.The primitive part itself is choosen such that it cannot be written as a non-trivial power of another element. It is a generator of the stabilizer of the corresponding (attracting) fixed point.
If
self
is elliptic then the primitive part is chosen as a conjugate ofS
orU
.Warning: The case
n=infinity
is not verified at all and probably wrong!INPUT:
method
– The method used to determine the primitivepart (see
primitive_representative()
), default: “cf”. The parameter is ignored for elliptic elements or +- the identity.The result should not depend on the method.
OUTPUT:
The primitive part as a group element of
self
.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: G.element_repr_method("block") sage: G.T().primitive_part() (T^(-1)*S) * (V(6)) * (T^(-1)*S)^(-1) sage: G.V(2).acton(G.T(-3)).primitive_part() (T) * (V(6)) * (T)^(-1) sage: (-G.V(2)).primitive_part() (T*S*T) * (V(2)) * (T*S*T)^(-1) sage: (-G.V(2)^3*G.V(6)^2*G.V(3)).primitive_part() V(2)^3*V(6)^2*V(3) sage: (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3)).primitive_part() (T*S*T*S*T*S*T^2*S*T) * (V(2)^3*V(6)^2*V(3)) * (T*S*T*S*T*S*T^2*S*T)^(-1) sage: (G.V(1)^5*G.V(2)*G.V(3)^3).primitive_part() (T^6*S*T) * (V(3)^3*V(1)^5*V(2)) * (T^6*S*T)^(-1) sage: (G.V(2)*G.V(3)).acton(G.U()^6).primitive_part() (-T*S*T^2*S*T*S*T) * (U) * (-T*S*T^2*S*T*S*T)^(-1) sage: (-G.I()).primitive_part() 1 sage: G.U().primitive_part() U sage: (-G.S()).primitive_part() S sage: el = (G.V(2)*G.V(3)).acton(G.U()^6) sage: el.primitive_part() (-T*S*T^2*S*T*S*T) * (U) * (-T*S*T^2*S*T*S*T)^(-1) sage: el.primitive_part() == el.primitive_part(method="block") True sage: G.T().primitive_part() (T^(-1)*S) * (V(6)) * (T^(-1)*S)^(-1) sage: G.T().primitive_part(method="block") (T^(-1)) * (V(1)) * (T^(-1))^(-1) sage: G.V(2).acton(G.T(-3)).primitive_part() == G.V(2).acton(G.T(-3)).primitive_part(method="block") True sage: (-G.V(2)).primitive_part() == (-G.V(2)).primitive_part(method="block") True sage: el = -G.V(2)^3*G.V(6)^2*G.V(3) sage: el.primitive_part() == el.primitive_part(method="block") True sage: el = (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3)) sage: el.primitive_part() == el.primitive_part(method="block") True sage: el=G.V(1)^5*G.V(2)*G.V(3)^3 sage: el.primitive_part() == el.primitive_part(method="block") True sage: G.element_repr_method("default")
- primitive_power(method='cf')#
Return the primitive power of
self
. I.e. an integerpower
such thatself = sign * primitive_part^power
, wheresign = self.sign()
andprimitive_part = self.primitive_part(method)
.Warning: For the parabolic case the sign depends on the method: The “cf” method may return a negative power but the “block” method never will.
Warning: The case
n=infinity
is not verified at all and probably wrong!INPUT:
method
– The method used to determine the primitivepower (see
primitive_representative()
), default: “cf”. The parameter is ignored for elliptic elements or +- the identity.
OUTPUT:
An integer. For +- the identity element
0
is returned, for parabolic and hyperbolic elements a positive integer. And for elliptic elements a (non-zero) integer with minimal absolute value such thatprimitive_part^power
still has a positive sign.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: G.T().primitive_power() -1 sage: G.V(2).acton(G.T(-3)).primitive_power() 3 sage: (-G.V(2)^2).primitive_power() 2 sage: el = (-G.V(2)*G.V(6)*G.V(3)*G.V(2)*G.V(6)*G.V(3)) sage: el.primitive_power() 2 sage: (G.U()^4*G.S()*G.V(2)).acton(el).primitive_power() 2 sage: (G.V(2)*G.V(3)).acton(G.U()^6).primitive_power() -1 sage: G.V(2).acton(G.T(-3)).primitive_power() == G.V(2).acton(G.T(-3)).primitive_power(method="block") True sage: (-G.I()).primitive_power() 0 sage: G.U().primitive_power() 1 sage: (-G.S()).primitive_power() 1 sage: el = (G.V(2)*G.V(3)).acton(G.U()^6) sage: el.primitive_power() -1 sage: el.primitive_power() == (-el).primitive_power() True sage: (G.U()^(-6)).primitive_power() 1 sage: G = HeckeTriangleGroup(n=8) sage: (G.U()^4).primitive_power() 4 sage: (G.U()^(-4)).primitive_power() 4
- primitive_representative(method='block')#
Return a tuple
(P, R)
which gives the decomposition of the primitive part ofself
, namelyR*P*R.inverse()
into a specific representativeP
and the corresponding conjugation matrixR
(the result depends on the method used).Together they describe the primitive part of self. I.e. an element which is equal to
self
up to a sign after taking the appropriate power.See
_primitive_block_decomposition_data()
for a description about the representative in case the default methodblock
is used. Also seeprimitive_part()
to construct the primitive part ofself
.Warning: The case
n=infinity
is not verified at all and probably wrong!INPUT:
method
–block
(default) orcf
. The methodused to determine
P
andR
. Ifself
is elliptic this parameter is ignored and ifself
is +- the identity then theblock
method is used.With
block
the decomposition described in_primitive_block_decomposition_data()
is used.With
cf
a reduced representative from the lambda-CF ofself
is used (seecontinued_fraction()
). In that caseP
corresponds to the period andR
to the preperiod.
OUTPUT:
A tuple
(P, R)
of group elements such thatR*P*R.inverse()
is a/the primitive part ofself
EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: G.element_repr_method("basic") sage: el = G.T().primitive_representative(method="cf") sage: el (S*T^(-1)*S*T^(-1)*S*T*S, S*T*S) sage: (el[0]).is_primitive() True sage: el = G.V(2).acton(G.T(-3)).primitive_representative(method="cf") sage: el (-T*S*T^(-1)*S*T^(-1), 1) sage: (el[0]).is_primitive() True sage: el = (-G.V(2)).primitive_representative(method="cf") sage: el (T^2*S, T*S) sage: (el[0]).is_primitive() True sage: el = (-G.V(2)^3*G.V(6)^2*G.V(3)).primitive_representative(method="cf") sage: el (-T^2*S*T^2*S*T*S*T^(-2)*S*T*S*T*S*T^2*S, T*S) sage: (el[0]).is_primitive() True sage: el = (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3)).primitive_representative(method="cf") sage: el (-T^2*S*T^2*S*T^2*S*T*S*T^(-2)*S*T*S*T*S, T*S*T*S*T*S*T^2*S) sage: (el[0]).is_primitive() True sage: el = (G.V(1)^5*G.V(2)*G.V(3)^3).primitive_representative(method="cf") sage: el (T^2*S*T*S*T^2*S*T*S*T^2*S*T*S*T^7*S, T^6*S) sage: (el[0]).is_primitive() True sage: el = (G.V(2)*G.V(3)).acton(G.U()^6).primitive_representative(method="cf") sage: el (T*S, -T*S*T^2*S*T*S*T) sage: (el[0]).is_primitive() True sage: G.element_repr_method("block") sage: el = G.T().primitive_representative() sage: (el[0]).is_primitive() True sage: el = G.V(2).acton(G.T(-3)).primitive_representative() sage: el ((-S*T^(-1)*S) * (V(6)) * (-S*T^(-1)*S)^(-1), (T^(-1)) * (V(1)) * (T^(-1))^(-1)) sage: (el[0]).is_primitive() True sage: el = (-G.V(2)).primitive_representative() sage: el ((T*S*T) * (V(2)) * (T*S*T)^(-1), (T*S*T) * (V(2)) * (T*S*T)^(-1)) sage: (el[0]).is_primitive() True sage: el = (-G.V(2)^3*G.V(6)^2*G.V(3)).primitive_representative() sage: el (V(2)^3*V(6)^2*V(3), 1) sage: (el[0]).is_primitive() True sage: el = (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3)).primitive_representative() sage: el (V(2)^3*V(6)^2*V(3), (T*S*T*S*T*S*T) * (V(2)*V(4)) * (T*S*T*S*T*S*T)^(-1)) sage: (el[0]).is_primitive() True sage: el = (G.V(1)^5*G.V(2)*G.V(3)^3).primitive_representative() sage: el (V(3)^3*V(1)^5*V(2), (T^6*S*T) * (V(1)^5*V(2)) * (T^6*S*T)^(-1)) sage: (el[0]).is_primitive() True sage: G.element_repr_method("default") sage: el = G.I().primitive_representative() sage: el ( [1 0] [1 0] [0 1], [0 1] ) sage: (el[0]).is_primitive() True sage: el = G.U().primitive_representative() sage: el ( [lam -1] [1 0] [ 1 0], [0 1] ) sage: (el[0]).is_primitive() True sage: el = (-G.S()).primitive_representative() sage: el ( [ 0 -1] [-1 0] [ 1 0], [ 0 -1] ) sage: (el[0]).is_primitive() True sage: el = (G.V(2)*G.V(3)).acton(G.U()^6).primitive_representative() sage: el ( [lam -1] [-2*lam^2 - 2*lam + 2 -2*lam^2 - 2*lam + 1] [ 1 0], [ -2*lam^2 + 1 -2*lam^2 - lam + 2] ) sage: (el[0]).is_primitive() True
- rational_period_function(k)#
The method assumes that
self
is hyperbolic.Return the rational period function of weight
k
for the primitive conjugacy class ofself
.A \(rational period function\) of weight
k
is a rational functionq
which satisfies:q + q|S == 0
andq + q|U + q|U^2 + ... + q|U^(n-1) == 0
, whereS = self.parent().S()
,U = self.parent().U()
and|
is the usual \(slash-operator\) of weight \(k\). Note that ifk < 0
thenq
is a polynomial.This method returns a very basic rational period function associated with the primitive conjugacy class of
self
. The (strong) expectation is that all rational period functions are formed by linear combinations of such functions.There is also a close relation with modular integrals of weight
2-k
and sometimes2-k
is used for the weight instead ofk
.Warning: The case
n=infinity
is not verified at all and probably wrong!EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=5) sage: S = G.S() sage: U = G.U() sage: def is_rpf(f, k=None): ....: if not f + S.slash(f, k=k) == 0: ....: return False ....: if not sum([(U^m).slash(f, k=k) for m in range(G.n())]) == 0: ....: return False ....: return True sage: z = PolynomialRing(G.base_ring(), 'z').gen() sage: [is_rpf(1 - z^(-k), k=k) for k in range(-6, 6, 2)] # long time [True, True, True, True, True, True] sage: [is_rpf(1/z, k=k) for k in range(-6, 6, 2)] [False, False, False, False, True, False] sage: el = G.V(2) sage: el.is_hecke_symmetric() False sage: rpf = el.rational_period_function(-4) sage: is_rpf(rpf) == is_rpf(rpf, k=-4) True sage: is_rpf(rpf) True sage: is_rpf(rpf, k=-6) False sage: is_rpf(rpf, k=2) False sage: rpf -lam*z^4 + lam sage: rpf = el.rational_period_function(-2) sage: is_rpf(rpf) True sage: rpf (lam + 1)*z^2 - lam - 1 sage: el.rational_period_function(0) == 0 True sage: rpf = el.rational_period_function(2) sage: is_rpf(rpf) True sage: rpf ((lam + 1)*z^2 - lam - 1)/(lam*z^4 + (-lam - 2)*z^2 + lam) sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6) sage: el.is_hecke_symmetric() False sage: rpf = el.rational_period_function(-6) sage: is_rpf(rpf) True sage: rpf (68*lam + 44)*z^6 + (-24*lam - 12)*z^4 + (24*lam + 12)*z^2 - 68*lam - 44 sage: rpf = el.rational_period_function(-2) sage: is_rpf(rpf) True sage: rpf (4*lam + 4)*z^2 - 4*lam - 4 sage: el.rational_period_function(0) == 0 True sage: rpf = el.rational_period_function(2) sage: is_rpf(rpf) == is_rpf(rpf, k=2) True sage: is_rpf(rpf) True sage: rpf.denominator() (8*lam + 5)*z^8 + (-94*lam - 58)*z^6 + (199*lam + 124)*z^4 + (-94*lam - 58)*z^2 + 8*lam + 5 sage: el = G.V(2)*G.V(3) sage: el.is_hecke_symmetric() True sage: el.rational_period_function(-4) == 0 True sage: rpf = el.rational_period_function(-2) sage: is_rpf(rpf) True sage: rpf (8*lam + 4)*z^2 - 8*lam - 4 sage: el.rational_period_function(0) == 0 True sage: rpf = el.rational_period_function(2) sage: is_rpf(rpf) True sage: rpf.denominator() (144*lam + 89)*z^8 + (-618*lam - 382)*z^6 + (951*lam + 588)*z^4 + (-618*lam - 382)*z^2 + 144*lam + 89 sage: el.rational_period_function(4) == 0 True
- reduce(primitive=True)#
Return a reduced version of
self
(with the same the same fixed points). Also seeis_reduced()
.If
self
is elliptic (or +- the identity) the result is never reduced (by definition). Instead a more canonical conjugation representative ofself
(resp. it’s primitive part) is choosen.Warning: The case
n=infinity
is not verified at all and probably wrong!INPUT:
primitive
– IfTrue
(default) then a primitiverepresentative for
self
is returned.
EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: print(G.T().reduce().string_repr("basic")) S*T^(-1)*S*T^(-1)*S*T*S sage: G.T().reduce().is_reduced(require_hyperbolic=False) True sage: print(G.V(2).acton(-G.T(-3)).reduce().string_repr("basic")) -T*S*T^(-1)*S*T^(-1) sage: print(G.V(2).acton(-G.T(-3)).reduce(primitive=False).string_repr("basic")) T*S*T^(-3)*S*T^(-1) sage: print((-G.V(2)).reduce().string_repr("basic")) T^2*S sage: (-G.V(2)).reduce().is_reduced() True sage: print((-G.V(2)^3*G.V(6)^2*G.V(3)).reduce().string_repr("block")) (-S*T^(-1)) * (V(2)^3*V(6)^2*V(3)) * (-S*T^(-1))^(-1) sage: (-G.V(2)^3*G.V(6)^2*G.V(3)).reduce().is_reduced() True sage: print((-G.I()).reduce().string_repr("block")) 1 sage: print(G.U().reduce().string_repr("block")) U sage: print((-G.S()).reduce().string_repr("block")) S sage: print((G.V(2)*G.V(3)).acton(G.U()^6).reduce().string_repr("block")) U sage: print((G.V(2)*G.V(3)).acton(G.U()^6).reduce(primitive=False).string_repr("block")) -U^(-1)
- reduced_elements()#
Return the cycle of reduced elements in the (primitive) conjugacy class of
self
.I.e. the set (cycle) of all reduced elements which are conjugate to
self.primitive_part()
. E.g.self.primitive_representative().reduce()
.Also see
is_reduced()
. In particular the result of this method only depends on the (primitive) conjugacy class ofself
.The method assumes that
self
is hyperbolic or parabolic.Warning: The case
n=infinity
is not verified at all and probably wrong!EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=5) sage: G.element_repr_method("basic") sage: el = G.V(1) sage: el.continued_fraction() ((0, 1), (1, 1, 2)) sage: R = el.reduced_elements() sage: R [T*S*T*S*T^2*S, T*S*T^2*S*T*S, -T*S*T^(-1)*S*T^(-1)] sage: [v.continued_fraction() for v in R] [((), (1, 1, 2)), ((), (1, 2, 1)), ((), (2, 1, 1))] sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6) sage: el.continued_fraction() ((1,), (3,)) sage: R = el.reduced_elements() sage: [v.continued_fraction() for v in R] [((), (3,))] sage: G.element_repr_method("default")
- root_extension_embedding(K=None)#
Return the correct embedding from the root extension field to
K
.INPUT:
K
– A field to which we want the (correct) embedding.If
K=None
(default) thenAlgebraicField()
is used for elliptic elements andAlgebraicRealField()
otherwise.
EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=infinity) sage: fp = (-G.S()).fixed_points()[0] sage: alg_fp = (-G.S()).root_extension_embedding()(fp) sage: alg_fp 1*I sage: alg_fp == (-G.S()).fixed_points(embedded=True)[0] True sage: fp = (-G.V(2)).fixed_points()[1] sage: alg_fp = (-G.V(2)).root_extension_embedding()(fp) sage: alg_fp -1.732050807568...? sage: alg_fp == (-G.V(2)).fixed_points(embedded=True)[1] True sage: fp = (-G.V(2)).fixed_points()[0] sage: alg_fp = (-G.V(2)).root_extension_embedding()(fp) sage: alg_fp 1.732050807568...? sage: alg_fp == (-G.V(2)).fixed_points(embedded=True)[0] True sage: G = HeckeTriangleGroup(n=7) sage: fp = (-G.S()).fixed_points()[1] sage: alg_fp = (-G.S()).root_extension_embedding()(fp) sage: alg_fp 0.?... - 1.000000000000...?*I sage: alg_fp == (-G.S()).fixed_points(embedded=True)[1] True sage: fp = (-G.U()^4).fixed_points()[0] sage: alg_fp = (-G.U()^4).root_extension_embedding()(fp) sage: alg_fp 0.9009688679024...? + 0.4338837391175...?*I sage: alg_fp == (-G.U()^4).fixed_points(embedded=True)[0] True sage: (-G.U()^4).root_extension_embedding(CC)(fp) 0.900968867902... + 0.433883739117...*I sage: (-G.U()^4).root_extension_embedding(CC)(fp).parent() Complex Field with 53 bits of precision sage: fp = (-G.V(5)).fixed_points()[1] sage: alg_fp = (-G.V(5)).root_extension_embedding()(fp) sage: alg_fp -0.6671145837954...? sage: alg_fp == (-G.V(5)).fixed_points(embedded=True)[1] True
- root_extension_field()#
Return a field extension which contains the fixed points of
self
. Namely the root extension field of the parent for the discriminant ofself
. Also see the parent methodroot_extension_field(D)
androot_extension_embedding()
(which provides the correct embedding).EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=infinity) sage: G.V(3).discriminant() 32 sage: G.V(3).root_extension_field() == G.root_extension_field(32) True sage: G.T().root_extension_field() == G.root_extension_field(G.T().discriminant()) == G.base_field() True sage: (G.S()).root_extension_field() == G.root_extension_field(G.S().discriminant()) True sage: G = HeckeTriangleGroup(n=7) sage: D = G.V(3).discriminant() sage: D 4*lam^2 + 4*lam - 4 sage: G.V(3).root_extension_field() == G.root_extension_field(D) True sage: G.U().root_extension_field() == G.root_extension_field(G.U().discriminant()) True sage: G.V(1).root_extension_field() == G.base_field() True
- sign()#
Return the sign element/matrix (+- identity) of
self
. The sign is given by the sign of the trace. if the trace is zero it is instead given by the sign of the lower left entry.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: (-G.T(-1)).sign() [-1 0] [ 0 -1] sage: G.S().sign() [1 0] [0 1] sage: (-G.S()).sign() [-1 0] [ 0 -1] sage: (G.U()^6).sign() [-1 0] [ 0 -1] sage: G = HeckeTriangleGroup(n=8) sage: (G.U()^4).trace() 0 sage: (G.U()^4).sign() [1 0] [0 1] sage: (G.U()^(-4)).sign() [-1 0] [ 0 -1]
- simple_elements()#
Return all simple elements in the primitive conjugacy class of
self
.I.e. the set of all simple elements which are conjugate to
self.primitive_part()
.Also see
is_simple()
. In particular the result of this method only depends on the (primitive) conjugacy class ofself
.The method assumes that
self
is hyperbolic.Warning: The case
n=infinity
is not verified at all and probably wrong!EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=5) sage: el = G.V(2) sage: el.continued_fraction() ((1,), (2,)) sage: R = el.simple_elements() sage: R [ [lam lam] [ 1 lam] ] sage: R[0].is_simple() True sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6) sage: el.continued_fraction() ((1,), (3,)) sage: R = el.simple_elements() sage: R [ [ 2*lam 2*lam + 1] [ lam 2*lam + 1] [ 1 lam], [ 1 2*lam] ] sage: [v.is_simple() for v in R] [True, True] sage: el = G.V(1)^2*G.V(2)*G.V(4) sage: el.discriminant() 135*lam + 86 sage: R = el.simple_elements() sage: R [ [ 3*lam 3*lam + 2] [8*lam + 3 3*lam + 2] [5*lam + 2 9*lam + 6] [3*lam + 4 6*lam + 3], [ lam + 2 lam], [ lam + 2 4*lam + 1], [2*lam + 1 7*lam + 4] [ lam + 2 7*lam + 2] ]
This agrees with the results (p.16) from Culp-Ressler on binary quadratic forms for Hecke triangle groups:
sage: [v.continued_fraction() for v in R] [((1,), (1, 1, 4, 2)), ((3,), (2, 1, 1, 4)), ((2,), (2, 1, 1, 4)), ((1,), (2, 1, 1, 4))]
- simple_fixed_point_set(extended=True)#
Return a set of all attracting fixed points in the conjugacy class of the primitive part of
self
.If
extended=True
(default) then alsoS.acton(alpha)
are added foralpha
in the set.This is a so called \(irreducible system of poles\) for rational period functions for the parent group. I.e. the fixed points occur as a irreducible part of the non-zero pole set of some rational period function and all pole sets are given as a union of such irreducible systems of poles.
The method assumes that
self
is hyperbolic.Warning: The case
n=infinity
is not verified at all and probably wrong!EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=5) sage: el = G.V(2) sage: el.simple_fixed_point_set() {1/2*e, (-1/2*lam + 1/2)*e} sage: el.simple_fixed_point_set(extended=False) {1/2*e} sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6) sage: el.simple_fixed_point_set() {(-lam + 3/2)*e + 1/2*lam - 1, (-lam + 3/2)*e - 1/2*lam + 1, 1/2*e - 1/2*lam, 1/2*e + 1/2*lam} sage: el.simple_fixed_point_set(extended=False) {1/2*e - 1/2*lam, 1/2*e + 1/2*lam}
- slash(f, tau=None, k=None)#
Return the \(slash-operator\) of weight
k
to applied tof
, evaluated attau
. I.e.(f|_k[self])(tau)
.INPUT:
f
– A function intau
(or an object for whichevaluation at
self.acton(tau)
makes sense.
tau
– Where to evaluate the result.This should be a valid argument for
acton()
.If
tau
is a point ofHyperbolicPlane()
then its coordinates in the upper half plane model are used.Default:
None
in which casef
has to be a rational function / polynomial in one variable and the generator of the polynomial ring is used fortau
. That wayslash
acts on rational functions / polynomials.
k
– An even integer.Default:
None
in which casef
either has to be a rational function / polynomial in one variable (then -degree is used). Orf
needs to have aweight
attribute which is then used.
EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: G = HeckeTriangleGroup(n=5) sage: E4 = ModularForms(group=G, k=4, ep=1).E4() sage: z = CC(-1/(-1/(2*i+30)-1)) sage: (G.S()).slash(E4, z) 32288.0558881... - 118329.856601...*I sage: (G.V(2)*G.V(3)).slash(E4, z) 32288.0558892... - 118329.856603...*I sage: E4(z) 32288.0558881... - 118329.856601...*I sage: z = HyperbolicPlane().PD().get_point(CC(-I/2 + 1/8)) sage: (G.V(2)*G.V(3)).slash(E4, z) -(21624.437... - 12725.035...*I)/((0.610... + 0.324...*I)*sqrt(5) + 2.720... + 0.648...*I)^4 sage: z = PolynomialRing(G.base_ring(), 'z').gen() sage: rat = z^2 + 1/(z-G.lam()) sage: dr = rat.numerator().degree() - rat.denominator().degree() sage: G.S().slash(rat) == G.S().slash(rat, tau=None, k=-dr) True sage: G.S().slash(rat) (z^6 - lam*z^4 - z^3)/(-lam*z^4 - z^3) sage: G.S().slash(rat, k=0) (z^4 - lam*z^2 - z)/(-lam*z^4 - z^3) sage: G.S().slash(rat, k=-4) (z^8 - lam*z^6 - z^5)/(-lam*z^4 - z^3)
- string_repr(method='default')#
Return a string representation of
self
using the specifiedmethod
. This method is used to representself
. The default representation method can be set for the parent withself.parent().element_repr_method(method)
.INPUT:
method
–default
: Use the usual representation method for matrix group elements.basic
: The representation is given as a word inS
and powers ofT
.Note: If
S, T
are defined accordingly the output can be used/evaluated directly to recoverself
.conj
: The conjugacy representative of the element is representedas a word in powers of the basic blocks, together with an unspecified conjugation matrix.
block
: Same asconj
but the conjugation matrix is specified as well.Note: Assuming
S, T, U, V
are defined accordingly the output can directly be used/evaluated to recoverself
.
Warning: For
n=infinity
the methodsconj
andblock
are not verified at all and are probably wrong!EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=5) sage: el1 = -G.I() sage: el2 = G.S()*G.T(3)*G.S()*G.T(-2) sage: el3 = G.V(2)*G.V(3)^2*G.V(4)^3 sage: el4 = G.U()^4 sage: el5 = (G.V(2)*G.T()).acton(-G.S()) sage: el4.string_repr(method="basic") 'S*T^(-1)' sage: G.element_repr_method("default") sage: el1 [-1 0] [ 0 -1] sage: el2 [ -1 2*lam] [ 3*lam -6*lam - 7] sage: el3 [34*lam + 19 5*lam + 4] [27*lam + 18 5*lam + 2] sage: el4 [ 0 -1] [ 1 -lam] sage: el5 [-7*lam - 4 9*lam + 6] [-4*lam - 5 7*lam + 4] sage: G.element_repr_method("basic") sage: el1 -1 sage: el2 S*T^3*S*T^(-2) sage: el3 -T*S*T*S*T^(-1)*S*T^(-2)*S*T^(-4)*S sage: el4 S*T^(-1) sage: el5 T*S*T^2*S*T^(-2)*S*T^(-1) sage: G.element_repr_method("conj") sage: el1 [-1] sage: el2 [-V(4)^2*V(1)^3] sage: el3 [V(3)^2*V(4)^3*V(2)] sage: el4 [-U^(-1)] sage: el5 [-S] sage: G.element_repr_method("block") sage: el1 -1 sage: el2 -(S*T^3) * (V(4)^2*V(1)^3) * (S*T^3)^(-1) sage: el3 (T*S*T) * (V(3)^2*V(4)^3*V(2)) * (T*S*T)^(-1) sage: el4 -U^(-1) sage: el5 -(T*S*T^2) * (S) * (T*S*T^2)^(-1) sage: G.element_repr_method("default") sage: G = HeckeTriangleGroup(n=infinity) sage: el = G.S()*G.T(3)*G.S()*G.T(-2) sage: print(el.string_repr()) [ -1 4] [ 6 -25] sage: print(el.string_repr(method="basic")) S*T^3*S*T^(-2)
- trace()#
Return the trace of
self
, which is the sum of the diagonal entries.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: G.U().trace() lam sage: G.S().trace() 0
- word_S_T()#
Decompose
self
into a product of the generatorsS
andT
of its parent, together with a sign correction matrix, namely:self = sgn * prod(L)
.Warning: If
self
is +- the identityprod(L)
is an empty product which produces1
instead of the identity matrix.OUTPUT:
The function returns a tuple
(L, sgn)
where the entries ofL
are either the generatorS
or a non-trivial integer power of the generatorT
.sgn
is +- the identity.If this decomposition is not possible a
TypeError
is raised.EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=17) sage: (-G.I()).word_S_T()[0] () sage: (-G.I()).word_S_T()[1] [-1 0] [ 0 -1] sage: (L, sgn) = (-G.V(2)).word_S_T() sage: L ( [ 1 lam] [ 0 -1] [ 1 lam] [ 0 1], [ 1 0], [ 0 1] ) sage: sgn == -G.I() True sage: -G.V(2) == sgn * prod(L) True sage: (L, sgn) = G.U().word_S_T() sage: L ( [ 1 lam] [ 0 -1] [ 0 1], [ 1 0] ) sage: sgn == G.I() True sage: G.U() == sgn * prod(L) True sage: G = HeckeTriangleGroup(n=infinity) sage: (L, sgn) = (-G.V(2)*G.V(3)).word_S_T() sage: L ( [1 2] [ 0 -1] [1 4] [ 0 -1] [1 2] [ 0 -1] [1 2] [0 1], [ 1 0], [0 1], [ 1 0], [0 1], [ 1 0], [0 1] ) sage: -G.V(2)*G.V(3) == sgn * prod(L) True
- sage.modular.modform_hecketriangle.hecke_triangle_group_element.coerce_AA(p)#
Return the argument first coerced into
AA
and then simplified.This leads to a major performance gain with some operations.
EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_group_element import coerce_AA sage: p = (791264*AA(2*cos(pi/8))^2 - 463492).sqrt() sage: AA(p)._exact_field() Number Field in a with defining polynomial y^8 ... with a in ... sage: coerce_AA(p)._exact_field() Number Field in a with defining polynomial y^4 - 1910*y^2 - 3924*y + 681058 with a in ...?
- sage.modular.modform_hecketriangle.hecke_triangle_group_element.cyclic_representative(L)#
Return a unique representative among all cyclic permutations of the given list/tuple.
INPUT:
L
– A list or tuple.
OUTPUT:
The maximal element among all cyclic permutations with respect to lexicographical ordering.
EXAMPLES:
sage: from sage.modular.modform_hecketriangle.hecke_triangle_group_element import cyclic_representative sage: cyclic_representative((1,)) (1,) sage: cyclic_representative((2,2)) (2, 2) sage: cyclic_representative((1,2,1,2)) (2, 1, 2, 1) sage: cyclic_representative((1,2,3,2,3,1)) (3, 2, 3, 1, 1, 2)