Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
r""" Hecke triangle group elements
AUTHORS:
- Jonas Jermann (2014): initial version
"""
#***************************************************************************** # Copyright (C) 2013-2014 Jonas Jermann <jjermann2@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #*****************************************************************************
# We want to simplify p after the coercion (pari bug for AA) r""" 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...? """ #el.exactify()
r""" 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) """
r""" Elements of HeckeTriangleGroup. """ r""" An element of HeckeTriangle group given by a matrix ``M``.
INPUT:
- ``parent`` -- A ``HeckeTriangleGroup``.
- ``M`` -- A matrix which coerces into the matrix space of ``parent``. For example with entries in a polynomial ring over ``ZZ`` with parameter ``lam``.
- ``check`` -- ``True`` (default) or ``False``. If ``True`` then a (possibly long) check is performed to see whether ``M`` really corresponds to a group element of ``parent``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup, HeckeTriangleGroupElement sage: lam = PolynomialRing(ZZ, 'lam').gen() sage: M = matrix([[-1, 0], [-lam^4 + 5*lam^2 + lam - 5, -1]]) sage: G = HeckeTriangleGroup(4) sage: G(M) Traceback (most recent call last): ... TypeError: The matrix is not an element of Hecke triangle group for n = 4, up to equivalence it identifies two nonequivalent points.
sage: G = HeckeTriangleGroup(10) sage: el = G(M) sage: el == HeckeTriangleGroupElement(G, M) True sage: type(el) <class 'sage.modular.modform_hecketriangle.hecke_triangle_groups.HeckeTriangleGroup_with_category.element_class'> sage: el.category() Category of elements of Hecke triangle group for n = 10 sage: type(HeckeTriangleGroupElement(G, M)) <class 'sage.modular.modform_hecketriangle.hecke_triangle_group_element.HeckeTriangleGroupElement'> sage: HeckeTriangleGroupElement(G, M).category() Category of elements of Hecke triangle group for n = 10 sage: el [ -1 0] [lam -1] sage: el.matrix().parent() Full MatrixSpace of 2 by 2 dense matrices over Maximal Order in Number Field in lam with defining polynomial x^4 - 5*x^2 + 5
sage: M = matrix([[-1, lam], [0, 1]]) sage: G(M) Traceback (most recent call last): ... TypeError: The matrix is not an element of Hecke triangle group for n = 10, it has determinant -1 != 1.
sage: G.T().inverse() [ 1 -lam] [ 0 1] sage: G.U() == G.T()*G.S() True sage: G.U()^(-10) == -G.I() True """
# The matrix check involves a lengthy element method (_word_S_T_data) # whose result is also used for other purposes. For performance reason the # results are stored/cached in the element. Moreover this avoids code duplication. # In particular this means we cannot call the method from _matrix_check(). # Instead it is called here in the __init__ method of the element # (after the preliminary checks).
def _word_S_T_data(self): r""" Return a tuple ``(L, sgn)`` which describes the decomposition of ``self`` as a product of the generators ``S`` and ``T`` together with a sign correction ``sgn``.
If this decomposition is not possible a ``TypeError`` is raised. In particular this function can be used to check the membership in ``parent`` of an arbitrary matrix over the base ring.
OUTPUT:
The tuple entries of ``L`` are either of the form ``(0, 1)``, corresponding to ``S`` or ``(1, m)`` corresponding to ``T^m``, where ``m`` is a non-trivial integer. ``sgn`` is +-1.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=17) sage: G.I()._word_S_T_data() ((), 1) sage: (-G.V(2))._word_S_T_data() (((1, 1), (0, 1), (1, 1)), -1) sage: G.U()._word_S_T_data() (((1, 1), (0, 1)), 1)
sage: G = HeckeTriangleGroup(n=infinity) sage: (-G.V(2)*G.V(3))._word_S_T_data() (((1, 1), (0, 1), (1, 2), (0, 1), (1, 1), (0, 1), (1, 1)), -1) sage: G.U()._word_S_T_data() (((1, 1), (0, 1)), 1) """
else:
r""" 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 """
else:
r""" Return the string representation of ``self``. The result depends on the default element representation method of the parent: ``self.parent().element_repr_method()``.
See :meth:`string_repr` for a list of possible methods and for more examples.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=5) sage: el = G.S()*G.T(3)*G.S()*G.T(-2) sage: el [ -1 2*lam] [ 3*lam -6*lam - 7] sage: el.string_repr() '[ -1 2*lam]\n[ 3*lam -6*lam - 7]' sage: G.element_repr_method("basic") sage: el S*T^3*S*T^(-2) sage: el.string_repr("basic") 'S*T^3*S*T^(-2)' """
r""" 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:
- ``method`` -- ``default``: 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) """
else: else:
from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
#if self != R.inverse().acton(self): else:
from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
else: pass else: else: exp = "({})".format(exp)
else: raise NotImplementedError
# We cache this method since the calculation is rather long and the # result is beeing reused: # - For block decompositions # - For calculating reduced (and simple) elements (and all dependent methods) def continued_fraction(self): r""" 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)) """ from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
raise NotImplementedError # Note: The algorithm still produces "something" # emb = self.root_extension_embedding(QQbar) raise NotImplementedError
# TODO: The choice of r doesn't matter? #elif self.is_elliptic(): # r = ZZ(emb(p/lam).real().floor() + 1) else:
# TODO: allow output as word? # We cache this method since the calculation is rather long and the # data is beeing reused when working with primitive representatives # and conjugacy classes. def _primitive_block_decomposition_data(self): r""" Return a tuple ``(L, R)`` which describes the decomposition of ``self`` into a very specific primitive conjugacy representative whose decomposition is further described by the tuple ``L``, and the corresponding conjugation matrix ``R``.
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 and which itself cannot be written as a non-trivial power (at least for non-elliptic elements).
To construct the representative see :meth:`primitive_representative`. To construct the primitive part see :meth:`primitive_part`. To get a corresponding decomposition of ``self`` see :meth:`block_decomposition`.
In the hyperbolic and parabolic case the representative is given as a product of powers of ``V(j)`` (more precisely ``self.parent().V(j)``), where ``1 <= j <= n-1``.
The number of such factors is called ``block length`` (see :meth:`block_length`). Each block (and also their product) has a positive sign and non-negative entries.
In the elliptic case the primitive representative is either ``S`` or ``U``.
Warning: The case ``n=infinity`` is not verified at all and probably wrong!
OUTPUT:
A tuple ``(L, R)``, where ``R`` is an element of the Hecke triangle group that conjugates the described primitive representative to the primitive part of ``self``.
In the hyperbolic and parabolic case ``L`` is an ordered tuple of (tuple) data ``(j, k)``, corresponding to a factor ``V(j)^k``.
If the representative is the identity then ``((1,0),)`` is returned (consistent with the previous notation).
In the elliptic case ``L=(a, 1)``, with either ``a=0`` corresponding to the representative ``S`` or ``a=1`` corresponding to the representative ``U``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: G.element_repr_method("basic")
sage: (L, R) = G.T()._primitive_block_decomposition_data() sage: L ((1, 1),) sage: R T^(-1) sage: (L, R) = G.V(2).acton(G.T(-3))._primitive_block_decomposition_data() sage: L ((6, 1),) sage: R T sage: (L, R) = (-G.V(2))._primitive_block_decomposition_data() sage: L ((2, 1),) sage: R T*S*T sage: (L, R) = (-G.V(2)^3*G.V(6)^2*G.V(3))._primitive_block_decomposition_data() sage: L ((2, 3), (6, 2), (3, 1)) sage: R 1 sage: (L, R) = (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3))._primitive_block_decomposition_data() sage: L ((2, 3), (6, 2), (3, 1)) sage: R T*S*T*S*T*S*T^2*S*T sage: (L, R) = (G.V(1)^5*G.V(2)*G.V(3)^3)._primitive_block_decomposition_data() sage: L ((3, 3), (1, 5), (2, 1)) sage: R T^6*S*T
sage: G.element_repr_method("default") sage: (L, R) = G.I()._primitive_block_decomposition_data() sage: L ((6, 0),) sage: R [1 0] [0 1]
sage: (L, R) = G.U()._primitive_block_decomposition_data() sage: L (1, 1) sage: R [1 0] [0 1] sage: (L, R) = (-G.S())._primitive_block_decomposition_data() sage: L (0, 1) sage: R [-1 0] [ 0 -1] sage: (L, R) = (G.V(2)*G.V(3)).acton(G.U()^6)._primitive_block_decomposition_data() sage: L (1, 1) sage: R [-2*lam^2 - 2*lam + 2 -2*lam^2 - 2*lam + 1] [ -2*lam^2 + 1 -2*lam^2 - lam + 2] """ from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
# The elliptic case (for this case we use a special notation): raise NotImplementedError
# we should have: embw == emb(w)
else: raise RuntimeError("There is something wrong in the method " "_primitive_block_decomposition_data. Please contact sage-devel@googlegroups.com")
# The identity case (consistent with the notation in the parabolic case):
# The hyperbolic and parabolic case: # The parabolic case is much simpler but the same algorithm # as in the hyperbolic case still works
else:
list_v1 = [-ZZ(1)] list_vlarger = [ initial_ones + 2 ] else:
else: else:
# This should determine whether self is conjugate to a positive power of V(1) or V(n-1) # sign((a+d)*(b-c)) is actually a conjugacy invariant for the parabolic subspace # and distinguishes the two (three) cases (sign(0):=0) # In this case self should be conjugate to a positive power of V(1) # in either case L is / should be (at the moment) always equal to [n-1, 1]
r""" 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 :meth:`_primitive_block_decomposition_data` for a description about the representative in case the default method ``block`` is used. Also see :meth:`primitive_part` to construct the primitive part of ``self``.
Warning: The case ``n=infinity`` is not verified at all and probably wrong!
INPUT:
- ``method`` -- ``block`` (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 :meth:`_primitive_block_decomposition_data` is used.
With ``cf`` a reduced representative from the lambda-CF of ``self`` is used (see :meth:`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 """ from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
raise NotImplementedError
else:
else: raise ValueError("if the element is not elliptic, then method must " "be either be 'cf' or 'block'")
r""" 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 :meth:`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") """ from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
r""" Return a reduced version of ``self`` (with the same the same fixed points). Also see :meth:`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) """ from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
else:
r""" 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] """
else: else: raise AssertionError("This shouldn't happen!")
r""" 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 :meth:`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 """ from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
raise NotImplementedError
else:
else: raise RuntimeError("There is a problem in the method " "'primitive_power'. Please contact sage-devel@googlegroups.com")
# for the cases fom here on the sign has to be adjusted to the # sign of self (in self._block_decomposition_data()) return -j else: return j + G.n()
else:
r""" 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 :meth:`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 """ from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
else:
raise NotImplementedError
else:
#@cached_method r""" Return a tuple ``(L, R, sgn)`` which describes the decomposition of ``self`` into a specific conjugacy representative whose decomposition is further described by the tuple ``L``. The conjugation matrix is returned as ``R`` and since all factors have a positive sign, the sign ``sgn`` of ``self`` is supplied as well as +- 1 (which corresponds to the sign of the sign matrix ``self.sign()``).
The function is a generalization of :meth:`_primitive_block_decomposition_data` (see for more information) to give the decomposition data for possibly non-primitive elements.
Also see :meth:`block_decomposition()` for more information on the block decomposition.
Warning: The case ``n=infinity`` is not verified at all and probably wrong!
OUTPUT:
A tuple ``(L, R, sgn)``, where ``R`` is an element of the Hecke triangle group that conjugates the described representative to ``self`` up to the given sign.
In the hyperbolic and parabolic case ``L`` is an ordered tuple of (tuple) data ``(j, k)``, corresponding to a factor ``V(j)^k``.
If the representative is the identity then ``((1, 0))`` is returned (consistent with the previous notation).
In the elliptic case ``L=(a, k)``, with either ``a=0`` corresponding to the representative ``S^k`` or with ``a=1`` corresponding to the representative ``U^k``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(n=7) sage: G.element_repr_method("basic")
sage: (L, R, sgn) = G.T()._block_decomposition_data() sage: (L, sgn) (((1, 1),), 1) sage: R T^(-1) sage: (L, R, sgn) = G.V(2).acton(G.T(-3))._block_decomposition_data() sage: (L, sgn) (((6, 3),), 1) sage: R T sage: (L, R, sgn) = (-G.V(2)^2)._block_decomposition_data() sage: (L, sgn) (((2, 2),), -1) sage: R T*S*T sage: el = (-G.V(2)*G.V(6)*G.V(3)*G.V(2)*G.V(6)*G.V(3)) sage: (L, R, sgn) = el._block_decomposition_data() sage: (L, sgn) (((6, 1), (3, 1), (2, 1), (6, 1), (3, 1), (2, 1)), -1) sage: R T*S*T sage: (L, R, sgn) = (G.U()^4*G.S()*G.V(2)).acton(el)._block_decomposition_data() sage: (L, sgn) (((2, 1), (6, 1), (3, 1), (2, 1), (6, 1), (3, 1)), -1) sage: R T*S*T*S*T*S*T^2*S*T sage: (L, R, sgn) = (G.V(1)^5*G.V(2)*G.V(3)^3)._block_decomposition_data() sage: (L, sgn) (((3, 3), (1, 5), (2, 1)), 1) sage: R T^6*S*T
sage: G.element_repr_method("default") sage: (L, R, sgn) = (-G.I())._block_decomposition_data() sage: (L, sgn) (((6, 0),), -1) sage: R [1 0] [0 1] sage: (L, R, sgn) = G.U()._block_decomposition_data() sage: (L, sgn) ((1, 1), 1) sage: R [1 0] [0 1] sage: (L, R, sgn) = (-G.S())._block_decomposition_data() sage: (L, sgn) ((0, 1), -1) sage: R [-1 0] [ 0 -1] sage: (L, R, sgn) = (G.V(2)*G.V(3)).acton(G.U()^6)._block_decomposition_data() sage: (L, sgn) ((1, -1), -1) sage: R [-2*lam^2 - 2*lam + 2 -2*lam^2 - 2*lam + 1] [ -2*lam^2 + 1 -2*lam^2 - lam + 2] sage: (L, R, sgn) = (G.U()^(-6))._block_decomposition_data() sage: (L, sgn) ((1, 1), -1) sage: R [1 0] [0 1]
sage: G = HeckeTriangleGroup(n=8) sage: (L, R, sgn) = (G.U()^4)._block_decomposition_data() sage: (L, sgn) ((1, 4), 1) sage: R [1 0] [0 1] sage: (L, R, sgn) = (G.U()^(-4))._block_decomposition_data() sage: (L, sgn) ((1, 4), -1) sage: R [1 0] [0 1] """ from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
else:
raise NotImplementedError
# Since L is primitive L[1] should be equal to 1
# If the length of L is 1, there is always at most one block # Note that this is includes the parabolic case # Since L is primitive L[0][1] should be equal to 1 # Also note that in the non-elliptic case: # abs(self.primitive_power()) == self.primitive_power(method="block") else:
r""" 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 :meth:`_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] ) """ from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
else:
raise NotImplementedError
else: else:
r""" 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)) """ from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
else:
r""" 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 :meth:`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") """ from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
raise NotImplementedError
continue else:
r""" 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 :meth:`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))] """ from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
return []
r""" 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} """ from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
raise NotImplementedError
r""" Return the LaTeX representation of ``self``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: V = HeckeTriangleGroup(17).V(13) sage: latex(V) \begin{pmatrix} \mathit{\lambda}^{3} - 2 \mathit{\lambda} & \mathit{\lambda}^{2} - 1 \\ \mathit{\lambda}^{4} - 3 \mathit{\lambda}^{2} + 1 & \mathit{\lambda}^{3} - 2 \mathit{\lambda} \end{pmatrix} """
r""" Return the group element corresponding to the negative of the underlying matrix.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: U = HeckeTriangleGroup(n=7).U() sage: -U [-lam 1] [ -1 0] """
r""" Return the corresponding rows/entries of the underlying matrix.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: U = HeckeTriangleGroup(n=7).U() sage: U[0] (lam, -1) sage: U[0].parent() Ambient free module of rank 2 over the principal ideal domain Maximal Order in Number Field in lam with defining polynomial x^3 - x^2 - 2*x + 1 sage: U[1][0] 1 sage: U[1][0].parent() Maximal Order in Number Field in lam with defining polynomial x^3 - x^2 - 2*x + 1 """
r""" 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 """
r""" 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 """
r""" 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 """
r""" 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 """
r""" 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 """
r""" 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? """
r""" 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 """
else:
r""" 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 """
r""" 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 """
r""" 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 """ return False
r""" 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 """ else:
r""" 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 """
r""" 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 """ from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
raise NotImplementedError
# if this is not up-to-sign then a factor 2 should # be added before (the second) self.parent().n() else:
r""" 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 """ from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
else:
r""" 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 """
# The last condition is/should be equivalent to:
r""" 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()`` beeing 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: el.simple_fixed_point_set() {(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 """ from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
raise NotImplementedError
r""" 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: uniq([ is_rpf(1 - z^(-k), k=k) for k in range(-6, 6, 2)]) # long time [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 """ from warnings import warn warn("The case n=infinity here is not verified at all and probably wrong!")
raise NotImplementedError("This method is not implemented for the identity or elliptic element")
raise TypeError except TypeError: raise ValueError("k={} must be an even integer!".format(k))
r""" 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 = - 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 = - 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... """ return ZZ.zero()
else: else:
r""" 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 :meth:`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 """
r""" Return the correct embedding from the root extension field to ``K``.
INPUT:
- ``K`` -- A field to which we want the (correct) embeddding. 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 """
r""" 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 """ else: else:
sgn = coerce_AA(c).sign() else: sgn = coerce_AA(c).sign() else: else: raise NotImplementedError
r""" 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(1 + i/2) 2/5*I - 4/5 sage: G.S().acton(1 + i/2).parent() Symbolic Ring 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 """
# if tau is a point of HyperbolicPlane then we use it's coordinates in the UHP model
else: else:
else:
r""" Define the action by linear fractional transformation of Hecke triangle group elements on complex points (using :meth:`acton`).
For the action on matrices by conjugation :meth:`acton` has to be used explicitly (to avoid confusion/ambiguity in expressions of the form gamma1*gamma2*z).
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: G = HeckeTriangleGroup(5) sage: p = HyperbolicPlane().PD().get_point(I) sage: G.U()*p Boundary point in PD 1/2*(sqrt(5) - 2*I + 1)/(-1/2*I*sqrt(5) - 1/2*I + 1) sage: G.S()*G.U()*p == G.S()*(G.U()*p) True sage: G.S()*G.U()*p == (G.S()*G.U())*p True sage: (G.S()*G.U())*p == G.S()*(G.U()*p) True
sage: p = G.lam() sage: G.U()*G.T()*p 1/2*lam + 1/2 sage: p = QQbar(i*sqrt(2)) sage: G.U()*p 1.618033988749895? + 0.7071067811865475?*I sage: p = CC(-i + sqrt(2)) sage: G.U()*p 1.14662946795886 - 0.333333333333333*I sage: p = infinity sage: G.U()*p lam """
return None
r""" 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 :meth:`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) """
else: except (ValueError, TypeError, AttributeError): raise ValueError("The weight k could not be determined automatically and needs to be specified manually!")
raise TypeError except TypeError: raise ValueError("k={} must be an even integer!".format(k))
except (ValueError, TypeError, AttributeError): raise ValueError("f={} is not a rational function or a polynomial in one variable, so tau has to be specified explicitely!".format(f))
r""" 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 """ |