Path: blob/master/sage/modular/arithgroup/farey_symbol.pyx
4102 views
r"""1Farey Symbol for arithmetic subgroups of `{\rm PSL}_2(\ZZ)`23AUTHORS:45- Hartmut Monien (08 - 2011)67based on the *KFarey* package by Chris Kurth. Implemented as C++ module8for speed.9"""10#*****************************************************************************11# Copyright (C) 2011 Hartmut Monien <[email protected]>12#13# Distributed under the terms of the GNU General Public License (GPL)14#15# This code is distributed in the hope that it will be useful,16# but WITHOUT ANY WARRANTY; without even the implied warranty of17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU18# General Public License for more details.19#20# The full text of the GPL is available at:21#22# http://www.gnu.org/licenses/23#*****************************************************************************2425include '../../ext/interrupt.pxi'26include '../../ext/stdsage.pxi'27include '../../ext/cdefs.pxi'2829include "farey.pxd"3031import sage.rings.arith32from sage.rings.all import CC, RR33from sage.rings.integer cimport Integer34from sage.rings.infinity import infinity35from congroup_gammaH import is_GammaH36from congroup_gamma1 import is_Gamma137from congroup_gamma0 import is_Gamma038from congroup_gamma import is_Gamma39from congroup_sl2z import SL2Z40from sage.modular.cusps import Cusp4142from sage.plot.all import Graphics43from sage.plot.colors import to_mpl_color44from sage.plot.misc import options, rename_keyword45from sage.plot.all import hyperbolic_arc, hyperbolic_triangle, text4647cdef class Farey:48r"""49A class for calculating Farey symbols of arithmetics subgroups of50`{\rm PSL}_2(\ZZ)`. The arithmetic subgroup can be either any of51the congruence subgroups implemented in Sage, i.e. Gamma, Gamma0,52Gamma1 and GammaH or a subgroup of `{\rm PSL}_2(\ZZ)` which is53given by a user written helper class defining membership in that54group.5556REFERENCES:5758- Ravi S. Kulkarni, ''An arithmetic-geometric method in the study of the59subgroups of the modular group'', `Amer. J. Math., 113(6):1053--1133,601991. <http://www.jstor.org/stable/2374900>`_6162INPUTS:6364- `G` - an arithmetic subgroup of `{\rm PSL}_2(\ZZ)`6566EXAMPLES:6768Create a Farey symbol for the group `\Gamma_0(11)`::6970sage: F = FareySymbol(Gamma0(11)); F71FareySymbol(Congruence Subgroup Gamma0(11))7273Calculate the generators::7475sage: F.generators()76[77[1 1] [ 7 -2] [ 8 -3] [-1 0]78[0 1], [11 -3], [11 -4], [ 0 -1]79]8081Pickling the FareySymbol and recovering it::8283sage: F == loads(dumps(F))84True8586Calculate the index of `\Gamma_H(33, [2, 5])` in87`{\rm PSL}_2(\ZZ)` via FareySymbol::8889sage: FareySymbol(GammaH(33, [2, 5])).index()90489192Calculate the generators of `\Gamma_1(4)`::9394sage: FareySymbol(Gamma1(4)).generators()95[96[1 1] [-3 1]97[0 1], [-4 1]98]99100Calculate the generators of the :meth:`example101<sage.modular.arithgroup.arithgroup_perm.HsuExample10>` of an102index 10 arithmetic subgroup given by Tim Hsu::103104sage: from sage.modular.arithgroup.arithgroup_perm import HsuExample10105sage: FareySymbol(HsuExample10()).generators()106[107[1 2] [-2 1] [ 4 -3]108[0 1], [-7 3], [ 3 -2]109]110111Calculate the generators of the group `\Gamma' =112\Gamma_0(8)\cap\Gamma_1(4)` using a helper class to define group membership::113114sage: class GPrime:115... def __contains__(self, M):116... return M in Gamma0(8) and M in Gamma1(4)117...118119sage: FareySymbol(GPrime()).generators()120[121[1 1] [ 5 -1] [ 5 -2]122[0 1], [16 -3], [ 8 -3]123]124125Calculate cusps of arithmetic subgroup defined via permutation group::126127sage: L = SymmetricGroup(4)('(1, 2, 3)')128129sage: R = SymmetricGroup(4)('(1, 2, 4)')130131sage: FareySymbol(ArithmeticSubgroup_Permutation(L, R)).cusps()132[2, Infinity]133134Calculate the left coset representation of `\Gamma_H(8, [3])`::135136sage: FareySymbol(GammaH(8, [3])).coset_reps()137[138[1 0] [ 4 -1] [ 3 -1] [ 2 -1] [ 1 -1] [ 3 -1] [ 2 -1] [-1 0]139[0 1], [ 1 0], [ 1 0], [ 1 0], [ 1 0], [ 4 -1], [ 3 -1], [ 3 -1],140[ 1 -1] [-1 0] [ 0 -1] [-1 0]141[ 2 -1], [ 2 -1], [ 1 -1], [ 1 -1]142]143"""144cdef cpp_farey *this_ptr145cdef object group146147def __cinit__(self, group, data=None):148r"""149Initialize FareySymbol::150151sage: FareySymbol(Gamma0(23))152FareySymbol(Congruence Subgroup Gamma0(23))153"""154self.group = group155# if data is present we want to restore156if data is not None:157self.this_ptr = new cpp_farey(data)158return159## to accelerate the calculation of the FareySymbol160## we implement the tests for the standard congruence groups161## in the c++ module. For a general group the test if an element162## of SL2Z is in the group the python __contains__ attribute163## of the group is called164cdef int p165if hasattr(group, "level"): p=group.level()166if group == SL2Z:167sig_on()168self.this_ptr = new cpp_farey()169sig_off()170elif is_Gamma0(group):171sig_on()172self.this_ptr = new cpp_farey(group, new is_element_Gamma0(p))173sig_off()174elif is_Gamma1(group):175sig_on()176self.this_ptr = new cpp_farey(group, new is_element_Gamma1(p))177sig_off()178elif is_Gamma(group):179sig_on()180self.this_ptr = new cpp_farey(group, new is_element_Gamma(p))181sig_off()182elif is_GammaH(group):183sig_on()184l = group._GammaH_class__H185self.this_ptr = new cpp_farey(group, new is_element_GammaH(p, l))186sig_off()187else:188sig_on()189self.this_ptr = new cpp_farey(group)190sig_off()191192def __deallocpp__(self):193r"""194Remove reference to FareySymbol::195196sage: F = FareySymbol(Gamma0(23))197198sage: del F199200"""201del self.this_ptr202203def __cmp__(self, other):204r"""205Compare self to others.206207EXAMPLES::208209sage: FareySymbol(Gamma(2)) == FareySymbol(Gamma0(7))210False211212sage: FareySymbol(Gamma0(23)) == loads(dumps(FareySymbol(Gamma0(23))))213True214"""215cmp_fcts = [lambda fs: fs.coset_reps(),216lambda fs: fs.cusps(),217lambda fs: fs.fractions()]218219for cf in cmp_fcts:220c = cmp(cf(self), cf(other))221if c != 0: return c222223return c224225def __reduce__(self):226r"""227Serialization for pickling::228229sage: FareySymbol(Gamma0(4)).__reduce__()230(<type 'sage.modular.arithgroup.farey_symbol.Farey'>, ...))231232"""233return Farey, (self.group, self.this_ptr.dumps())234235def __repr__(self):236r"""237Return the string representation of self.238239EXAMPLES::240241sage: FareySymbol(Gamma0(23)).__repr__()242'FareySymbol(Congruence Subgroup Gamma0(23))'243"""244if hasattr(self.group, "_repr_"):245return "FareySymbol(%s)" % self.group._repr_()246elif hasattr(self.group, "__repr__"):247return "FareySymbol(%s)" % self.group.__repr__()248else:249return "FareySymbol(?)"250251def _latex_(self):252r"""253Return the LaTeX representation of self.254255EXAMPLES::256257sage: FareySymbol(Gamma0(23))._latex_()258'\\mathcal{F}(\\Gamma_0(23))'259"""260if hasattr(self.group, "_latex_"):261return "\mathcal{F}(%s)" % self.group._latex_()262else:263return "\mathcal{F}(%s)" % "unknonwn"264265def index(self):266r"""267Return the index of the arithmetic group of the FareySymbol268in `{\rm PSL}_2(\ZZ)`.269270EXAMPLES::271272sage: [FareySymbol(Gamma0(n)).index() for n in range(1, 16)]273[1, 3, 4, 6, 6, 12, 8, 12, 12, 18, 12, 24, 14, 24, 24]274"""275return self.this_ptr.index()276277def genus(self):278r"""279Return the genus of the arithmetic group of the FareySymbol.280281EXAMPLES::282283sage: [FareySymbol(Gamma0(n)).genus() for n in range(16, 32)]284[0, 1, 0, 1, 1, 1, 2, 2, 1, 0, 2, 1, 2, 2, 3, 2]285"""286return self.this_ptr.genus()287288def level(self):289r"""290Return the level of the arithmetic group of the FareySymbol.291292EXAMPLES::293294sage: [FareySymbol(Gamma0(n)).level() for n in range(1, 16)]295[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]296"""297return self.this_ptr.level();298299def nu2(self):300r"""301Return the number of elliptic points of order two.302303EXAMPLES::304305sage: [FareySymbol(Gamma0(n)).nu2() for n in range(1, 16)]306[1, 1, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0]307"""308return self.this_ptr.nu2()309310def nu3(self):311r"""312Return the number of elliptic points of order three.313314EXAMPLES::315316sage: [FareySymbol(Gamma0(n)).nu3() for n in range(1, 16)]317[1, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0]318"""319return self.this_ptr.nu3()320321def coset_reps(self):322r"""323Left coset of the arithmetic group of the FareySymbol.324325EXAMPLES:326327Calculate the left coset of `\Gamma_0(6)`::328329sage: FareySymbol(Gamma0(6)).coset_reps()330[331[1 0] [ 3 -1] [ 2 -1] [ 1 -1] [ 2 -1] [ 3 -2] [ 1 -1] [-1 0]332[0 1], [ 1 0], [ 1 0], [ 1 0], [ 3 -1], [ 2 -1], [ 2 -1], [ 2 -1],333[ 1 -1] [ 0 -1] [-1 0] [-2 1]334[ 3 -2], [ 1 -1], [ 1 -1], [ 1 -1]335]336"""337return self.this_ptr.get_coset()338339def generators(self):340r"""341Minmal set of generators of the group of the FareySymbol.342343EXAMPLES:344345Calculate the generators of `\Gamma_0(6)`::346347sage: FareySymbol(Gamma0(6)).generators()348[349[1 1] [ 5 -1] [ 7 -3] [-1 0]350[0 1], [ 6 -1], [12 -5], [ 0 -1]351]352353Calculate the generators of `{\rm SL}_2(\ZZ)`::354355sage: FareySymbol(SL2Z).generators()356[357[ 0 -1] [ 0 -1]358[ 1 0], [ 1 -1]359]360361The unique index 2 even subgroup and index 4 odd subgroup each get handled correctly::362363sage: FareySymbol(ArithmeticSubgroup_Permutation(S2="(1,2)", S3="()")).generators()364[365[ 0 -1] [-1 1]366[ 1 1], [-1 0]367]368sage: FareySymbol(ArithmeticSubgroup_Permutation(S2="(1,2, 3, 4)", S3="(1,3)(2,4)")).generators()369[370[ 0 1] [-1 1]371[-1 -1], [-1 0]372]373"""374return self.this_ptr.get_generators()375376def fractions(self):377r"""378Fractions of the FareySymbol.379380EXAMPLES::381382sage: FareySymbol(Gamma(4)).fractions()383[0, 1/2, 1, 3/2, 2, 5/2, 3, 7/2, 4]384"""385return self.this_ptr.get_fractions()386387388def pairings(self):389r"""390Pairings of the sides of the fundamental domain of the Farey symbol391of the arithmetic group. The sides of the hyperbolic polygon are392numbered 0, 1, ... from left to right. Conventions: even pairings are393denoted by -2, odd pairings by -3 while free pairings are denoted by394an integer number greater than zero.395396EXAMPLES:397398Odd pairings::399400sage: FareySymbol(Gamma0(7)).pairings()401[1, -3, -3, 1]402403Even and odd pairings::404405FareySymbol(Gamma0(13)).pairings()406[1, -3, -2, -2, -3, 1]407408Only free pairings::409410sage: FareySymbol(Gamma0(23)).pairings()411[1, 2, 3, 5, 3, 4, 2, 4, 5, 1]412"""413return self.this_ptr.get_pairings()414415def paired_sides(self):416r"""417Pairs of index of the sides of the fundamental domain of the418Farey symbol of the arithmetic group. The sides of the419hyperbolic polygon are numbered 0, 1, ... from left to right.420421.. image:: ../../../media/modular/arithgroup/pairing.png422423EXAMPLES::424425sage: FareySymbol(Gamma0(11)).paired_sides()426[(0, 5), (1, 3), (2, 4)]427428indicating that the side 0 is paired with 5, 1 with 3 and 2 with 4.429"""430return self.this_ptr.get_paired_sides()431432def pairing_matrices(self):433r"""434Pairing matrices of the sides of the fundamental domain. The sides435of the hyperbolic polygon are numbered 0, 1, ... from left to right.436437EXAMPLES::438439sage: FareySymbol(Gamma0(6)).pairing_matrices()440[441[1 1] [ 5 -1] [ 7 -3] [ 5 -3] [ 1 -1] [-1 1]442[0 1], [ 6 -1], [12 -5], [12 -7], [ 6 -5], [ 0 -1]443]444"""445446return self.this_ptr.get_pairing_matrices()447448def cusps(self):449r"""450Cusps of the FareySymbol.451452EXAMPLES::453454sage: FareySymbol(Gamma0(6)).cusps()455[0, 1/3, 1/2, Infinity]456"""457return self.this_ptr.get_cusps()+[Cusp(infinity)]458459@rename_keyword(color='rgbcolor')460@options(alpha=1, fill=True, thickness=1, rgbcolor="lightgray", \461zorder=2, linestyle='solid', show_pairing=True, \462show_tesselation=False)463464def fundamental_domain(self, **options):465r"""466Plot a fundamental domain of an arithmetic subgroup of467`{\rm PSL}_2(\ZZ)` corresponding to the Farey symbol.468469OPTIONS:470471- ``fill`` - fill the fundamental domain (default True)472473- ``rgbcolor`` - fill color (default 'lightgray')474475- ``show_pairing`` - flag for pairing (default True)476477- ``show_tesselation`` - flag for the hyperbolic tesselation478(default False)479480EXAMPLES:481482For example to plot the fundamental domain of `\Gamma_0(11)`483with pairings use the following command::484485sage: FareySymbol(Gamma0(11)).fundamental_domain()486487indicating that side 1 is paired with side 3 and side 2 is488paired with side 4, see also :meth:`.paired_sides`.489490To plot the fundamental domain of `\Gamma(3)` without pairings491use the following command::492493sage: FareySymbol(Gamma(3)).fundamental_domain(show_pairing=False)494495Plot the fundamental domain of `\Gamma_0(23)` showing the left496coset representatives.497498::499500sage: FareySymbol(Gamma0(23)).fundamental_domain(show_tesselation=True)501"""502from sage.plot.colors import rainbow503L = 1000504g = Graphics()505## show coset506for x in self.coset_reps():507if self.index() != 2:508a, b, c, d = x[1, 1], -x[0, 1], -x[1, 0], x[0, 0]509A, B = CC(0, L), CC(0, L)510if d!=0: A = b/d511if c!=0: B = a/c512C = (a*c+b*d+(a*d+b*c)/2+CC(0, 1)*RR(3).sqrt()/2)\513/(c*c+c*d+d*d)514else:515A, B, C = [x.acton(z) for z in [CC(0, 0), CC(1, 0), CC(0, L)]]516g += hyperbolic_triangle(A, B, C, \517color=options['rgbcolor'], \518fill=options['fill'], \519alpha=options['alpha'])520if options['show_tesselation']:521g += hyperbolic_triangle(A, B, C, color="gray")522## show pairings523p = self.pairings()524x = self.fractions()525if options['show_pairing']:526rc = rainbow(max(p)-min(p)+1)527if p[0] > 0:528g += hyperbolic_arc(CC(0, L), x[0], color=rc[p[0]-min(p)])529if p[-1] > 0:530g += hyperbolic_arc(CC(0, L), x[-1], color=rc[p[-1]-min(p)])531for i in range(len(x)-1):532if p[i+1] > 0:533g += hyperbolic_arc(x[i], x[i+1], color=rc[p[i+1]-min(p)])534d = g.get_minmax_data()535g.set_axes_range(d['xmin'], d['xmax'], 0, 1)536return g537538539#--- conversions ------------------------------------------------------------540541cdef public long convert_to_long(n):542cdef long m = n543return m544545cdef public object convert_to_Integer(mpz_class a):546A = Integer()547A.set_from_mpz(a.get_mpz_t())548return A549550cdef public object convert_to_rational(mpq_class r):551a = Integer(); a.set_from_mpz(r.get_num_mpz_t())552b = Integer(); b.set_from_mpz(r.get_den_mpz_t())553return a/b554555cdef public object convert_to_cusp(mpq_class r):556a = Integer(); a.set_from_mpz(r.get_num_mpz_t())557b = Integer(); b.set_from_mpz(r.get_den_mpz_t())558return Cusp(a/b)559560cdef public object convert_to_SL2Z(cpp_SL2Z M):561a = convert_to_Integer(M.a())562b = convert_to_Integer(M.b())563c = convert_to_Integer(M.c())564d = convert_to_Integer(M.d())565return SL2Z([a, b, c, d])566567568