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: sage.groups.matrix_gps.group_element.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 of self by linear fractional transformations or by conjugation in case tau is an element of the parent of self.

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 of self or any

    element 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 of HyperbolicPlane() (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 that self = 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) for 1 <= j <= n-1. In the elliptic case the tuple entries are either S or U.

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 of self described in primitive_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 and discriminant >= block_length^2 * lambda^2 - 4.

Warning: The case n=infinity is not verified at all and probably wrong!

INPUT:

  • primitive – If True then the conjugacy

    representative 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 – If True (default) then the conjugacy

    classes are only considered up to a sign.

  • primitive – If True then the conjugacy class of

    the 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 for j >= 0. A finite lambda-CF is defined as: [r_0; r_1, ..., r_k] := (T^(r_0)*S* ... *T^(r_k)*S)(infinity), where S and T are the generators of self. 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] with n-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 of self.

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 – If True the fixed points are embedded into

    AlgebraicRealField resp. AlgebraicField. Default: False.

  • order – If order="none" the fixed points are choosen

    and 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 of self 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 of self. 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 either AlgebraicRealField or AlgebraicField 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 form Q.

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 of self 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 – If True (default) then non-primitive elements

    are not considered reduced.

  • require_hyperbolic – If True (default) then non-hyperbolic elements

    are 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 where alpha 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. If exclude_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 of E2 in the sense: lambda/(2*pi*i) d/dz g = E2. Let gamma=self and let M_gamma(z) be Log((c*z+d) * sgn(a+d)) if c, a+d > 0, resp. Log((c*z+d) / i*sgn(c)) if a+d = 0, c!=0, resp. 0 if c=0. Let k=4 * n / (n-2), then:

g(gamma.acton(z) - g(z) - k*M_gamma(z) is equal to 2*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 case n=3 this is the linking number of the closed geodesic (corresponding to self) 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 element A with non-negative trace such that self = sign * A^power, where sign = self.sign() is +- the identity (to correct the sign) and power = 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 of S or U.

Warning: The case n=infinity is not verified at all and probably wrong!

INPUT:

  • method – The method used to determine the primitive

    part (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 integer power such that self = sign * primitive_part^power, where sign = self.sign() and primitive_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 primitive

    power (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 that primitive_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 of self, namely R*P*R.inverse() into a specific representative P and the corresponding conjugation matrix R (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 method block is used. Also see primitive_part() to construct the primitive part of self.

Warning: The case n=infinity is not verified at all and probably wrong!

INPUT:

  • methodblock (default) or cf. The method

    used to determine P and R. If self is elliptic this parameter is ignored and if self is +- the identity then the block method is used.

    With block the decomposition described in _primitive_block_decomposition_data() is used.

    With cf a reduced representative from the lambda-CF of self is used (see continued_fraction()). In that case P corresponds to the period and R to the preperiod.

OUTPUT:

A tuple (P, R) of group elements such that R*P*R.inverse() is a/the primitive part of self

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 of self.

A \(rational period function\) of weight k is a rational function q which satisfies: q + q|S == 0 and q + q|U + q|U^2 + ... + q|U^(n-1) == 0, where S = self.parent().S(), U = self.parent().U() and | is the usual \(slash-operator\) of weight \(k\). Note that if k < 0 then q 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 sometimes 2-k is used for the weight instead of k.

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 see is_reduced().

If self is elliptic (or +- the identity) the result is never reduced (by definition). Instead a more canonical conjugation representative of self (resp. it’s primitive part) is choosen.

Warning: The case n=infinity is not verified at all and probably wrong!

INPUT:

  • primitive – If True (default) then a primitive

    representative 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 of self.

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) then AlgebraicField() is used for elliptic elements and AlgebraicRealField() 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 of self. Also see the parent method root_extension_field(D) and root_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 of self.

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 also S.acton(alpha) are added for alpha 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 to f, evaluated at tau. I.e. (f|_k[self])(tau).

INPUT:

  • f – A function in tau (or an object for which

    evaluation 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 of HyperbolicPlane() then its coordinates in the upper half plane model are used.

    Default: None in which case f has to be a rational function / polynomial in one variable and the generator of the polynomial ring is used for tau. That way slash acts on rational functions / polynomials.

  • k – An even integer.

    Default: None in which case f either has to be a rational function / polynomial in one variable (then -degree is used). Or f needs to have a weight 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 specified method. This method is used to represent self. The default representation method can be set for the parent with self.parent().element_repr_method(method).

INPUT:

  • methoddefault: Use the usual representation method for matrix group elements.

    basic: The representation is given as a word in S and powers of T.

    Note: If S, T are defined accordingly the output can be used/evaluated directly to recover self.

    conj: The conjugacy representative of the element is represented

    as a word in powers of the basic blocks, together with an unspecified conjugation matrix.

    block: Same as conj 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 recover self.

Warning: For n=infinity the methods conj and block 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 generators S and T of its parent, together with a sign correction matrix, namely: self = sgn * prod(L).

Warning: If self is +- the identity prod(L) is an empty product which produces 1 instead of the identity matrix.

OUTPUT:

The function returns a tuple (L, sgn) where the entries of L are either the generator S or a non-trivial integer power of the generator T. 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 39.710518724...?
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)