Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/modular/arithgroup/farey_symbol.pyx
8821 views
1
r"""
2
Farey Symbol for arithmetic subgroups of `{\rm PSL}_2(\ZZ)`
3
4
AUTHORS:
5
6
- Hartmut Monien (08 - 2011)
7
8
based on the *KFarey* package by Chris Kurth. Implemented as C++ module
9
for speed.
10
"""
11
#*****************************************************************************
12
# Copyright (C) 2011 Hartmut Monien <[email protected]>
13
#
14
# Distributed under the terms of the GNU General Public License (GPL)
15
#
16
# This code is distributed in the hope that it will be useful,
17
# but WITHOUT ANY WARRANTY; without even the implied warranty of
18
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19
# General Public License for more details.
20
#
21
# The full text of the GPL is available at:
22
#
23
# http://www.gnu.org/licenses/
24
#*****************************************************************************
25
26
include 'sage/ext/interrupt.pxi'
27
include 'sage/ext/stdsage.pxi'
28
include 'sage/ext/cdefs.pxi'
29
30
include "farey.pxd"
31
32
import sage.rings.arith
33
from sage.rings.all import CC, RR
34
from sage.rings.integer cimport Integer
35
from sage.rings.infinity import infinity
36
from congroup_gammaH import is_GammaH
37
from congroup_gamma1 import is_Gamma1
38
from congroup_gamma0 import is_Gamma0
39
from congroup_gamma import is_Gamma
40
from congroup_sl2z import SL2Z
41
from sage.modular.cusps import Cusp
42
43
from sage.plot.all import Graphics
44
from sage.plot.colors import to_mpl_color
45
from sage.plot.misc import options, rename_keyword
46
from sage.plot.all import hyperbolic_arc, hyperbolic_triangle, text
47
48
from sage.misc.latex import latex
49
50
cdef class Farey:
51
r"""
52
A class for calculating Farey symbols of arithmetics subgroups of
53
`{\rm PSL}_2(\ZZ)`. The arithmetic subgroup can be either any of
54
the congruence subgroups implemented in Sage, i.e. Gamma, Gamma0,
55
Gamma1 and GammaH or a subgroup of `{\rm PSL}_2(\ZZ)` which is
56
given by a user written helper class defining membership in that
57
group.
58
59
REFERENCES:
60
61
- Ravi S. Kulkarni, ''An arithmetic-geometric method in the study of the
62
subgroups of the modular group'', `Amer. J. Math., 113(6):1053--1133,
63
1991. <http://www.jstor.org/stable/2374900>`_
64
65
INPUTS:
66
67
- `G` - an arithmetic subgroup of `{\rm PSL}_2(\ZZ)`
68
69
EXAMPLES:
70
71
Create a Farey symbol for the group `\Gamma_0(11)`::
72
73
sage: f = FareySymbol(Gamma0(11)); f
74
FareySymbol(Congruence Subgroup Gamma0(11))
75
76
Calculate the generators::
77
78
sage: f.generators()
79
[
80
[1 1] [ 7 -2] [ 8 -3] [-1 0]
81
[0 1], [11 -3], [11 -4], [ 0 -1]
82
]
83
84
Pickling the FareySymbol and recovering it::
85
86
sage: f == loads(dumps(f))
87
True
88
89
Calculate the index of `\Gamma_H(33, [2, 5])` in
90
`{\rm PSL}_2(\ZZ)` via FareySymbol::
91
92
sage: FareySymbol(GammaH(33, [2, 5])).index()
93
48
94
95
Calculate the generators of `\Gamma_1(4)`::
96
97
sage: FareySymbol(Gamma1(4)).generators()
98
[
99
[1 1] [-3 1]
100
[0 1], [-4 1]
101
]
102
103
Calculate the generators of the :meth:`example
104
<sage.modular.arithgroup.arithgroup_perm.HsuExample10>` of an
105
index 10 arithmetic subgroup given by Tim Hsu::
106
107
sage: from sage.modular.arithgroup.arithgroup_perm import HsuExample10
108
sage: FareySymbol(HsuExample10()).generators()
109
[
110
[1 2] [-2 1] [ 4 -3]
111
[0 1], [-7 3], [ 3 -2]
112
]
113
114
Calculate the generators of the group `\Gamma' =
115
\Gamma_0(8)\cap\Gamma_1(4)` using a helper class to define group membership::
116
117
sage: class GPrime:
118
... def __contains__(self, M):
119
... return M in Gamma0(8) and M in Gamma1(4)
120
...
121
122
sage: FareySymbol(GPrime()).generators()
123
[
124
[1 1] [ 5 -1] [ 5 -2]
125
[0 1], [16 -3], [ 8 -3]
126
]
127
128
Calculate cusps of arithmetic subgroup defined via permutation group::
129
130
sage: L = SymmetricGroup(4)('(1, 2, 3)')
131
132
sage: R = SymmetricGroup(4)('(1, 2, 4)')
133
134
sage: FareySymbol(ArithmeticSubgroup_Permutation(L, R)).cusps()
135
[-1, Infinity]
136
137
Calculate the left coset representation of `\Gamma_H(8, [3])`::
138
139
sage: FareySymbol(GammaH(8, [3])).coset_reps()
140
[
141
[1 0] [ 4 -1] [ 3 -1] [ 2 -1] [ 1 -1] [ 3 -1] [ 2 -1] [-1 0]
142
[0 1], [ 1 0], [ 1 0], [ 1 0], [ 1 0], [ 4 -1], [ 3 -1], [ 3 -1],
143
[ 1 -1] [-1 0] [ 0 -1] [-1 0]
144
[ 2 -1], [ 2 -1], [ 1 -1], [ 1 -1]
145
]
146
"""
147
cdef cpp_farey *this_ptr
148
cdef object group
149
150
def __cinit__(self, group, data=None):
151
r"""
152
Initialize FareySymbol::
153
154
sage: FareySymbol(Gamma0(23))
155
FareySymbol(Congruence Subgroup Gamma0(23))
156
"""
157
self.group = group
158
# if data is present we want to restore
159
if data is not None:
160
sig_on()
161
self.this_ptr = new cpp_farey(data)
162
sig_off()
163
return
164
## to accelerate the calculation of the FareySymbol
165
## we implement the tests for the standard congruence groups
166
## in the c++ module. For a general group the test if an element
167
## of SL2Z is in the group the python __contains__ attribute
168
## of the group is called
169
cdef int p
170
if hasattr(group, "level"): p=group.level()
171
if group == SL2Z:
172
sig_on()
173
self.this_ptr = new cpp_farey()
174
sig_off()
175
elif is_Gamma0(group):
176
sig_on()
177
self.this_ptr = new cpp_farey(group, new is_element_Gamma0(p))
178
sig_off()
179
elif is_Gamma1(group):
180
sig_on()
181
self.this_ptr = new cpp_farey(group, new is_element_Gamma1(p))
182
sig_off()
183
elif is_Gamma(group):
184
sig_on()
185
self.this_ptr = new cpp_farey(group, new is_element_Gamma(p))
186
sig_off()
187
elif is_GammaH(group):
188
sig_on()
189
l = group._GammaH_class__H
190
self.this_ptr = new cpp_farey(group, new is_element_GammaH(p, l))
191
sig_off()
192
else:
193
sig_on()
194
self.this_ptr = new cpp_farey(group)
195
sig_off()
196
197
def __deallocpp__(self):
198
r"""
199
Remove reference to FareySymbol::
200
201
sage: F = FareySymbol(Gamma0(23))
202
203
sage: del F
204
205
"""
206
del self.this_ptr
207
208
def __contains__(self, M):
209
r"""
210
Tests if element is in the arithmetic group of the Farey symbol
211
via LLT algorithm.
212
213
EXAMPLES::
214
215
sage: SL2Z([0, -1, 1, 0]) in FareySymbol(Gamma0(6))
216
False
217
218
sage: SL2Z([1, 1, 0, 1]) in FareySymbol(Gamma0(6))
219
True
220
"""
221
cdef Integer a = M.a()
222
cdef Integer b = M.b()
223
cdef Integer c = M.c()
224
cdef Integer d = M.d()
225
sig_on()
226
result = self.this_ptr.is_element(a.value, b.value, c.value, d.value)
227
sig_off()
228
return result
229
230
def __cmp__(self, other):
231
r"""
232
Compare self to others.
233
234
EXAMPLES::
235
236
sage: FareySymbol(Gamma(2)) == FareySymbol(Gamma0(7))
237
False
238
239
sage: FareySymbol(Gamma0(23)) == loads(dumps(FareySymbol(Gamma0(23))))
240
True
241
"""
242
cmp_fcts = [lambda fs: fs.coset_reps(),
243
lambda fs: fs.cusps(),
244
lambda fs: fs.fractions()]
245
246
for cf in cmp_fcts:
247
c = cmp(cf(self), cf(other))
248
if c != 0: return c
249
250
return c
251
252
def __reduce__(self):
253
r"""
254
Serialization for pickling::
255
256
sage: FareySymbol(Gamma0(4)).__reduce__()
257
(<type 'sage.modular.arithgroup.farey_symbol.Farey'>, ...))
258
259
"""
260
return Farey, (self.group, self.this_ptr.dumps())
261
262
def __repr__(self):
263
r"""
264
Return the string representation of self.
265
266
EXAMPLES::
267
268
sage: FareySymbol(Gamma0(23)).__repr__()
269
'FareySymbol(Congruence Subgroup Gamma0(23))'
270
"""
271
if hasattr(self.group, "_repr_"):
272
return "FareySymbol(%s)" % self.group._repr_()
273
elif hasattr(self.group, "__repr__"):
274
return "FareySymbol(%s)" % self.group.__repr__()
275
else:
276
return "FareySymbol(?)"
277
278
def _latex_(self, forced_format = None):
279
r"""
280
Return the LaTeX representation of self.
281
282
INPUT:
283
284
- ``forced_format`` -- A format string ('plain' or 'xymatrix')
285
or ``None``.
286
287
EXAMPLES::
288
289
sage: FareySymbol(Gamma0(11))._latex_(forced_format = 'plain')
290
'\\left( -\\infty\\underbrace{\\quad}_{1} 0\\underbrace{\\quad}_{2} \\frac{1}{3}\\underbrace{\\quad}_{3} \\frac{1}{2}\\underbrace{\\quad}_{2} \\frac{2}{3}\\underbrace{\\quad}_{3} 1\\underbrace{\\quad}_{1} \\infty\\right)'
291
sage: FareySymbol(Gamma0(11))._latex_(forced_format = 'xymatrix')
292
'\\begin{xy}\\xymatrix{& -\\infty \\ar@{-}@/_1pc/[r]_{1}& 0 \\ar@{-}@/_1pc/[r]_{2}& \\frac{1}{3} \\ar@{-}@/_1pc/[r]_{3}& \\frac{1}{2} \\ar@{-}@/_1pc/[r]_{2}& \\frac{2}{3} \\ar@{-}@/_1pc/[r]_{3}& 1 \\ar@{-}@/_1pc/[r]_{1}& \\infty }\\end{xy}'
293
294
sage: if '\\xymatrix' in sage.misc.latex.latex.mathjax_avoid_list():
295
... 'xymatrix' not in FareySymbol(Gamma0(11))._latex_()
296
... else:
297
... 'xymatrix' in FareySymbol(Gamma0(11))._latex_()
298
True
299
"""
300
if forced_format == 'plain' or \
301
(forced_format is None and '\\xymatrix' in latex.mathjax_avoid_list()):
302
# output not using xymatrix
303
s = r'\left( -\infty'
304
a = [x._latex_() for x in self.fractions()] + ['\infty']
305
b = self.pairings()
306
for i in xrange(len(a)):
307
u = b[i]
308
if u == -3: u = r'\bullet'
309
elif u == -2: u = r'\circ'
310
s += r'\underbrace{\quad}_{%s} %s' % (u,a[i])
311
return s + r'\right)'
312
else:
313
# output using xymatrix
314
s = r'\begin{xy}\xymatrix{& -\infty '
315
f = [x._latex_() for x in self.fractions()]+[r'\infty']
316
f.reverse()
317
for p in self.pairings():
318
if p >= 0:
319
s += r'\ar@{-}@/_1pc/[r]_{%s}' % p
320
elif p == -2:
321
s += r'\ar@{-}@/_1pc/[r]_{\circ}'
322
elif p == -3:
323
s += r'\ar@{-}@/_1pc/[r]_{\bullet}'
324
s += r'& %s ' % f.pop()
325
s += r'}\end{xy}'
326
return s
327
328
def index(self):
329
r"""
330
Return the index of the arithmetic group of the FareySymbol
331
in `{\rm PSL}_2(\ZZ)`.
332
333
EXAMPLES::
334
335
sage: [FareySymbol(Gamma0(n)).index() for n in range(1, 16)]
336
[1, 3, 4, 6, 6, 12, 8, 12, 12, 18, 12, 24, 14, 24, 24]
337
"""
338
return self.this_ptr.index()
339
340
def genus(self):
341
r"""
342
Return the genus of the arithmetic group of the FareySymbol.
343
344
EXAMPLES::
345
346
sage: [FareySymbol(Gamma0(n)).genus() for n in range(16, 32)]
347
[0, 1, 0, 1, 1, 1, 2, 2, 1, 0, 2, 1, 2, 2, 3, 2]
348
"""
349
return self.this_ptr.genus()
350
351
def level(self):
352
r"""
353
Return the level of the arithmetic group of the FareySymbol.
354
355
EXAMPLES::
356
357
sage: [FareySymbol(Gamma0(n)).level() for n in range(1, 16)]
358
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
359
"""
360
return self.this_ptr.level();
361
362
def nu2(self):
363
r"""
364
Return the number of elliptic points of order two.
365
366
EXAMPLES::
367
368
sage: [FareySymbol(Gamma0(n)).nu2() for n in range(1, 16)]
369
[1, 1, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0]
370
"""
371
return self.this_ptr.nu2()
372
373
def nu3(self):
374
r"""
375
Return the number of elliptic points of order three.
376
377
EXAMPLES::
378
379
sage: [FareySymbol(Gamma0(n)).nu3() for n in range(1, 16)]
380
[1, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0]
381
"""
382
return self.this_ptr.nu3()
383
384
def coset_reps(self):
385
r"""
386
Left coset of the arithmetic group of the FareySymbol.
387
388
EXAMPLES:
389
390
Calculate the left coset of `\Gamma_0(6)`::
391
392
sage: FareySymbol(Gamma0(6)).coset_reps()
393
[
394
[1 0] [ 3 -1] [ 2 -1] [ 1 -1] [ 2 -1] [ 3 -2] [ 1 -1] [-1 0]
395
[0 1], [ 1 0], [ 1 0], [ 1 0], [ 3 -1], [ 2 -1], [ 2 -1], [ 2 -1],
396
[ 1 -1] [ 0 -1] [-1 0] [-2 1]
397
[ 3 -2], [ 1 -1], [ 1 -1], [ 1 -1]
398
]
399
"""
400
return self.this_ptr.get_coset()
401
402
def generators(self):
403
r"""
404
Minmal set of generators of the group of the FareySymbol.
405
406
EXAMPLES:
407
408
Calculate the generators of `\Gamma_0(6)`::
409
410
sage: FareySymbol(Gamma0(6)).generators()
411
[
412
[1 1] [ 5 -1] [ 7 -3] [-1 0]
413
[0 1], [ 6 -1], [12 -5], [ 0 -1]
414
]
415
416
Calculate the generators of `{\rm SL}_2(\ZZ)`::
417
418
sage: FareySymbol(SL2Z).generators()
419
[
420
[ 0 -1] [ 0 -1]
421
[ 1 0], [ 1 -1]
422
]
423
424
The unique index 2 even subgroup and index 4 odd subgroup each get handled correctly::
425
426
sage: FareySymbol(ArithmeticSubgroup_Permutation(S2="(1,2)", S3="()")).generators()
427
[
428
[ 0 1] [-1 1]
429
[-1 -1], [-1 0]
430
]
431
sage: FareySymbol(ArithmeticSubgroup_Permutation(S2="(1,2, 3, 4)", S3="(1,3)(2,4)")).generators()
432
[
433
[ 0 1] [-1 1]
434
[-1 -1], [-1 0]
435
]
436
"""
437
return self.this_ptr.get_generators()
438
439
def fractions(self):
440
r"""
441
Fractions of the FareySymbol.
442
443
EXAMPLES::
444
445
sage: FareySymbol(Gamma(4)).fractions()
446
[0, 1/2, 1, 3/2, 2, 5/2, 3, 7/2, 4]
447
"""
448
return self.this_ptr.get_fractions()
449
450
451
def pairings(self):
452
r"""
453
Pairings of the sides of the fundamental domain of the Farey symbol
454
of the arithmetic group. The sides of the hyperbolic polygon are
455
numbered 0, 1, ... from left to right. Conventions: even pairings are
456
denoted by -2, odd pairings by -3 while free pairings are denoted by
457
an integer number greater than zero.
458
459
EXAMPLES:
460
461
Odd pairings::
462
463
sage: FareySymbol(Gamma0(7)).pairings()
464
[1, -3, -3, 1]
465
466
Even and odd pairings::
467
468
FareySymbol(Gamma0(13)).pairings()
469
[1, -3, -2, -2, -3, 1]
470
471
Only free pairings::
472
473
sage: FareySymbol(Gamma0(23)).pairings()
474
[1, 2, 3, 5, 3, 4, 2, 4, 5, 1]
475
"""
476
return self.this_ptr.get_pairings()
477
478
def paired_sides(self):
479
r"""
480
Pairs of index of the sides of the fundamental domain of the
481
Farey symbol of the arithmetic group. The sides of the
482
hyperbolic polygon are numbered 0, 1, ... from left to right.
483
484
.. image:: ../../../media/pairing.png
485
486
EXAMPLES::
487
488
sage: FareySymbol(Gamma0(11)).paired_sides()
489
[(0, 5), (1, 3), (2, 4)]
490
491
indicating that the side 0 is paired with 5, 1 with 3 and 2 with 4.
492
"""
493
return self.this_ptr.get_paired_sides()
494
495
def pairing_matrices(self):
496
r"""
497
Pairing matrices of the sides of the fundamental domain. The sides
498
of the hyperbolic polygon are numbered 0, 1, ... from left to right.
499
500
EXAMPLES::
501
502
sage: FareySymbol(Gamma0(6)).pairing_matrices()
503
[
504
[1 1] [ 5 -1] [ 7 -3] [ 5 -3] [ 1 -1] [-1 1]
505
[0 1], [ 6 -1], [12 -5], [12 -7], [ 6 -5], [ 0 -1]
506
]
507
"""
508
509
return self.this_ptr.get_pairing_matrices()
510
511
def cusps(self):
512
r"""
513
Cusps of the FareySymbol.
514
515
EXAMPLES::
516
517
sage: FareySymbol(Gamma0(6)).cusps()
518
[0, 1/3, 1/2, Infinity]
519
"""
520
return self.this_ptr.get_cusps()+[Cusp(infinity)]
521
522
def cusp_widths(self):
523
r"""
524
Cusps widths of the FareySymbol.
525
526
EXAMPLES::
527
528
sage: FareySymbol(Gamma0(6)).cusp_widths()
529
[6, 2, 3, 1]
530
"""
531
return self.this_ptr.get_cusp_widths()
532
533
def cusp_class(self, c):
534
r"""
535
Cusp class of a cusp in the FareySymbol.
536
537
EXAMPLES::
538
539
sage: FareySymbol(Gamma0(12)).cusp_class(Cusp(1, 12))
540
5
541
"""
542
cusp = Cusp(c)
543
cdef Integer p = cusp.numerator()
544
cdef Integer q = cusp.denominator()
545
sig_on()
546
result = self.this_ptr.get_cusp_class(p.value, q.value)
547
sig_off()
548
return result
549
550
def reduce_to_cusp(self, r):
551
r"""
552
Transformation of a rational number to cusp representative.
553
554
EXAMPLES::
555
556
sage: FareySymbol(Gamma0(12)).reduce_to_cusp(5/8)
557
[ 5 -3]
558
[12 -7]
559
560
Reduce 11/17 to a cusp of for HsuExample10()::
561
562
sage: from sage.modular.arithgroup.arithgroup_perm import HsuExample10
563
sage: f = FareySymbol(HsuExample10())
564
sage: f.reduce_to_cusp(11/17)
565
[14 -9]
566
[-3 2]
567
sage: _.acton(11/17)
568
1
569
sage: f.cusps()[f.cusp_class(11/17)]
570
1
571
"""
572
cdef Integer p = r.numerator()
573
cdef Integer q = r.denominator()
574
sig_on()
575
result = self.this_ptr.get_transformation_to_cusp(p.value, q.value)
576
sig_off()
577
return result
578
579
@rename_keyword(rgbcolor='color')
580
@options(alpha=1, fill=True, thickness=1, color='lightgray', \
581
color_even='white', \
582
zorder=2, linestyle='solid', show_pairing=True, \
583
tesselation='Dedekind', ymax=1
584
)
585
def fundamental_domain(self, **options):
586
r"""
587
Plot a fundamental domain of an arithmetic subgroup of
588
`{\rm PSL}_2(\ZZ)` corresponding to the Farey symbol.
589
590
OPTIONS:
591
592
- ``fill`` -- boolean (default ``True``) fill the fundamental domain
593
594
- ``linestyle`` -- string (default: 'solid') The style of the line,
595
which is one of 'dashed', 'dotted', 'solid', 'dashdot', or '--',
596
':', '-', '-.', respectively
597
598
- ``color`` -- (default: 'lightgray') fill color; fill
599
color for odd part of Dedekind tesselation.
600
601
- ``show_pairing`` -- boolean (default: ``True``) flag for pairing
602
603
- ``tesselation`` -- (default: 'Dedekind') The type of
604
hyperbolic tesselation which is one of
605
'coset', 'Dedekind' or None respectively
606
607
- ``color_even`` -- fill color for even parts of Dedekind
608
tesselation (default 'white'); ignored for
609
other tesselations
610
611
- ``thickness`` -- float (default: `1`) the thickness of the line
612
613
- ``ymax`` -- float (default: `1`) maximal height
614
615
EXAMPLES:
616
617
For example, to plot the fundamental domain of `\Gamma_0(11)`
618
with pairings use the following command::
619
620
sage: FareySymbol(Gamma0(11)).fundamental_domain()
621
622
indicating that side 1 is paired with side 3 and side 2 is
623
paired with side 4, see also :meth:`.paired_sides`.
624
625
To plot the fundamental domain of `\Gamma(3)` without pairings
626
use the following command::
627
628
sage: FareySymbol(Gamma(3)).fundamental_domain(show_pairing=False)
629
630
Plot the fundamental domain of `\Gamma_0(23)` showing the left
631
coset representatives::
632
633
sage: FareySymbol(Gamma0(23)).fundamental_domain(tesselation='coset')
634
635
The same as above but with a custom linestyle::
636
637
sage: FareySymbol(Gamma0(23)).fundamental_domain(tesselation='coset', linestyle=':', thickness='2')
638
639
"""
640
from sage.plot.colors import rainbow
641
I = CC(0, 1)
642
w = RR(3).sqrt()
643
L = 1000
644
g = Graphics()
645
## show coset
646
for x in self.coset_reps():
647
a, b, c, d = x[1, 1], -x[0, 1], -x[1, 0], x[0, 0]
648
A, B = CC(0, L), CC(0, L)
649
if d!=0: A = b/d
650
if c!=0: B = a/c
651
C = (a*c+b*d+(a*d+b*c)/2+I*w/2)/(c*c+c*d+d*d)
652
D = (a*c+b*d + CC(0, 1))/(c*c+d*d)
653
if options['tesselation'] == 'Dedekind':
654
g += hyperbolic_triangle(A, D, C,
655
alpha=options['alpha'],
656
color=options['color'],
657
fill=options['fill'],
658
linestyle=options['linestyle'],
659
thickness=options['thickness'])
660
g += hyperbolic_triangle(D, C, B,
661
alpha=options['alpha'],
662
color=options['color_even'],
663
fill=options['fill'],
664
linestyle=options['linestyle'],
665
thickness=options['thickness'])
666
g += hyperbolic_triangle(A, D, C, color='gray')
667
g += hyperbolic_triangle(D, C, B, color='gray')
668
elif options['tesselation'] == 'coset':
669
g += hyperbolic_triangle(A, B, C,
670
alpha=options['alpha'],
671
color=options['color'],
672
fill=options['fill'],
673
linestyle=options['linestyle'],
674
thickness=options['thickness'])
675
g += hyperbolic_triangle(A, B, C, color='gray',
676
linestyle=options['linestyle'],
677
thickness=options['thickness'])
678
else:
679
g += hyperbolic_triangle(A, B, C,
680
alpha=options['alpha'],
681
color=options['color'],
682
fill=options['fill'],
683
linestyle=options['linestyle'],
684
thickness=options['thickness'])
685
## show pairings
686
p = self.pairings()
687
x = self.fractions()
688
if options['show_pairing']:
689
rc = rainbow(max(p)-min(p)+1)
690
if p[0] > 0:
691
g += hyperbolic_arc(CC(0, L), x[0], color=rc[p[0]-min(p)],
692
linestyle=options['linestyle'],
693
thickness=options['thickness'])
694
if p[-1] > 0:
695
g += hyperbolic_arc(CC(0, L), x[-1], color=rc[p[-1]-min(p)],
696
linestyle=options['linestyle'],
697
thickness=options['thickness'])
698
for i in range(len(x)-1):
699
if p[i+1] > 0:
700
g += hyperbolic_arc(x[i], x[i+1], color=rc[p[i+1]-min(p)],
701
linestyle=options['linestyle'],
702
thickness=options['thickness'])
703
d = g.get_minmax_data()
704
g.set_axes_range(d['xmin'], d['xmax'], 0, options['ymax'])
705
return g
706
707
708
#--- conversions ------------------------------------------------------------
709
710
cdef public long convert_to_long(n):
711
cdef long m = n
712
return m
713
714
cdef public object convert_to_Integer(mpz_class a):
715
A = Integer()
716
A.set_from_mpz(a.get_mpz_t())
717
return A
718
719
cdef public object convert_to_rational(mpq_class r):
720
a = Integer(); a.set_from_mpz(r.get_num_mpz_t())
721
b = Integer(); b.set_from_mpz(r.get_den_mpz_t())
722
return a/b
723
724
cdef public object convert_to_cusp(mpq_class r):
725
a = Integer(); a.set_from_mpz(r.get_num_mpz_t())
726
b = Integer(); b.set_from_mpz(r.get_den_mpz_t())
727
return Cusp(a/b)
728
729
cdef public object convert_to_SL2Z(cpp_SL2Z M):
730
a = convert_to_Integer(M.a())
731
b = convert_to_Integer(M.b())
732
c = convert_to_Integer(M.c())
733
d = convert_to_Integer(M.d())
734
return SL2Z([a, b, c, d])
735
736