Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/modular/arithgroup/farey.cpp
4038 views
1
//
2
// farey.cpp
3
//
4
// Implementation of FareySymbol
5
//
6
//****************************************************************************
7
// Copyright (C) 2011 Hartmut Monien <[email protected]>
8
// Stefan Krämer <[email protected]>
9
//
10
// Distributed under the terms of the GNU General Public License (GPL)
11
//
12
// This code is distributed in the hope that it will be useful,
13
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
// General Public License for more details.
16
//
17
// The full text of the GPL is available at:
18
//
19
// http://www.gnu.org/licenses/
20
//****************************************************************************
21
22
#include <vector>
23
#include <fstream>
24
#include <sstream>
25
#include <algorithm>
26
#include <cassert>
27
28
#include <gmpxx.h>
29
#include <Python.h>
30
31
#include "farey.hpp"
32
#include "farey_symbol.h"
33
34
using namespace std;
35
36
template <class T>
37
inline
38
ostream& operator<<(ostream& os, const vector<T>& v) {
39
os << v.size() << " ";
40
for(typename vector<T>::const_iterator i=v.begin(); i!=v.end(); i++) {
41
os << *i << " ";
42
}
43
return os;
44
}
45
46
template <class T>
47
inline
48
istream& operator>>(istream& is, vector<T>& v) {
49
size_t n;
50
is >> n;
51
for(size_t i=0; i<n; i++) {
52
T tmp;
53
is >> tmp;
54
v.push_back(tmp);
55
}
56
return is;
57
}
58
59
template <>
60
inline
61
istream& operator>>(istream& is, vector<SL2Z>& v) {
62
size_t n;
63
is >> n;
64
for(size_t i=0; i<n; i++) {
65
SL2Z tmp(1, 0, 0, 1);
66
is >> tmp;
67
v.push_back(tmp);
68
}
69
return is;
70
}
71
72
inline
73
istream& operator>>(istream& is, FareySymbol& F) {
74
is >> F.pairing_max
75
>> F.pairing
76
>> F.cusp_classes
77
>> F.a
78
>> F.b
79
>> F.x
80
>> F.coset
81
>> F.generators
82
>> F.cusps
83
>> F.cusp_widths;
84
return is;
85
}
86
87
inline
88
ostream& operator<<(ostream& os, const FareySymbol& F) {
89
os << F.pairing_max << " "
90
<< F.pairing
91
<< F.cusp_classes
92
<< F.a
93
<< F.b
94
<< F.x
95
<< F.coset
96
<< F.generators
97
<< F.cusps
98
<< F.cusp_widths;
99
return os;
100
}
101
102
inline
103
mpq_class operator/(const mpz_class& a, const mpz_class& b) {
104
return mpq_class(a, b);
105
}
106
107
inline
108
mpz_class lcm(const mpz_class& a, const mpz_class& b) {
109
mpz_class result;
110
mpz_lcm(result.get_mpz_t(), a.get_mpz_t(), b.get_mpz_t());
111
return result;
112
}
113
114
inline
115
mpz_class lcm(const vector<mpz_class>& v) {
116
mpz_class q(1);
117
for(size_t i=0; i<v.size(); i++) {
118
q = lcm(q, v[i]);
119
}
120
return q;
121
}
122
123
//--- Helper class for checking membership of SL2Z matrix in group GammaH ----
124
125
is_element_GammaH::is_element_GammaH(int p_, PyObject* gen_list) : p(p_) {
126
typedef vector<long>::const_iterator const_iterator;
127
// list of generators
128
vector<long> gen;
129
Py_ssize_t ngen = PyList_Size(gen_list);
130
for(Py_ssize_t i=0; i<ngen; i++) {
131
PyObject* item = PyList_GetItem(gen_list, i);
132
gen.push_back(convert_to_long(item));
133
}
134
// generate H from generators
135
H = gen;
136
for(;;) {
137
vector<long> m;
138
for(const_iterator i=gen.begin(); i!=gen.end(); i++) {
139
for(const_iterator j=H.begin(); j!=H.end(); j++) {
140
long q = ((*i)*(*j))%p;
141
if( find(H.begin(), H.end(), q) == H.end() and
142
find(m.begin(), m.end(), q) == m.end() ) {
143
m.push_back(q);
144
}
145
}
146
}
147
if( m.size() == 0 ) break;
148
for(const_iterator i=m.begin(); i!=m.end(); i++) H.push_back(*i);
149
}
150
// sort for binary searches
151
sort(H.begin(), H.end());
152
}
153
154
is_element_GammaH::~is_element_GammaH() {
155
}
156
157
bool is_element_GammaH::is_member(const SL2Z& m) const {
158
mpz_class a = m.a()%p; if(a < 0) a+=p;
159
mpz_class d = m.d()%p; if(d < 0) d+=p;
160
if( m.c()%p != 0 ) return false;
161
if( not binary_search(H.begin(), H.end(), a.get_si()) ) return false;
162
if( not binary_search(H.begin(), H.end(), d.get_si()) ) return false;
163
return true;
164
}
165
166
//--- Helper class for checking membership of SL2Z matrix in group -------------
167
// group defined by the python object.
168
169
is_element_general::is_element_general(PyObject* group_) : group(group_) {
170
if( PyObject_HasAttrString(group, "__contains__") ) {
171
method = PyObject_GetAttrString(group, "__contains__");
172
} else {
173
cerr << "group has to define __contains__" << endl;
174
throw string(__FUNCTION__) + ": error.";
175
}
176
}
177
178
is_element_general::~is_element_general() {
179
Py_DECREF(method);
180
}
181
182
bool is_element_general::is_member(const SL2Z& m) const {
183
PyObject* arg = convert_to_SL2Z(m);
184
PyObject* tuple = PyTuple_New(1);
185
PyTuple_SetItem(tuple, 0, arg);
186
PyObject *result = PyEval_CallObject(method, tuple);
187
Py_DECREF(tuple);
188
if( not PyBool_Check(result) ) {
189
cerr << "__contains__ does not return bool." << endl;
190
throw string(__FUNCTION__) + ": error.";
191
}
192
bool value = (result == Py_True);
193
Py_DECREF(result);
194
return value;
195
}
196
197
//--- FareySymbol ------------------------------------------------------------
198
199
// SL2Z
200
201
FareySymbol::FareySymbol() {
202
pairing = vector<int>(2);
203
pairing[0] = EVEN;
204
pairing[1] = ODD;
205
pairing_max = NO;
206
a.push_back(0);
207
b.push_back(1);
208
cusp_widths.push_back(1);
209
coset.push_back(SL2Z::E);
210
generators.push_back(SL2Z::S);
211
generators.push_back(SL2Z::S*SL2Z::R);
212
cusp_classes.push_back(1);
213
for(size_t i=0; i<a.size(); i++) x.push_back(a[i]/b[i]);
214
}
215
216
// User defined group and restoring from pickle
217
218
FareySymbol::FareySymbol(PyObject* o) {
219
if( PyString_Check(o) ) {
220
// restoration from data
221
istringstream is(PyString_AsString(o));
222
is >> (*this);
223
} else {
224
// init with user defined group
225
is_element_general *group = new is_element_general(o);
226
// check for user defined SL2Z
227
if( group->is_member(SL2Z::S) and
228
group->is_member(SL2Z::T) ) {
229
pairing = vector<int>(2);
230
pairing[0] = EVEN;
231
pairing[1] = ODD;
232
pairing_max = NO;
233
a.push_back(0);
234
b.push_back(1);
235
cusp_widths.push_back(1);
236
coset.push_back(SL2Z::E);
237
generators.push_back(SL2Z::S);
238
generators.push_back(SL2Z::S*SL2Z::R);
239
cusp_classes.push_back(1);
240
for(size_t i=0; i<a.size(); i++) x.push_back(a[i]/b[i]);
241
}
242
// check for index two subgroup
243
else if( group->is_member(SL2Z( 0, 1, -1, -1)) and
244
group->is_member(SL2Z(-1, 1, -1, 0)) ) {
245
pairing = vector<int>(2);
246
pairing[0] = ODD;
247
pairing[1] = ODD;
248
a.push_back(0);
249
b.push_back(1);
250
for(size_t i=0; i<a.size(); i++) x.push_back(a[i]/b[i]);
251
if ( group->is_member(SL2Z(0, -1, 1, 1)) )
252
// index 2 even subgroup
253
generators.push_back(SL2Z(0, -1, 1, 1));
254
else
255
// index 4 odd subgroup
256
generators.push_back(SL2Z(0, 1, -1, -1));
257
generators.push_back(SL2Z(-1, 1, -1, 0));
258
coset.push_back(SL2Z::E);
259
coset.push_back(SL2Z::T);
260
cusp_classes.push_back(1);
261
} else {
262
// everything else
263
init_pairing(group);
264
cusp_widths = init_cusp_widths();
265
coset = init_coset_reps();
266
generators = init_generators(group);
267
cusp_classes = init_cusp_classes();
268
for(size_t i=0; i<a.size(); i++) x.push_back(a[i]/b[i]);
269
cusps = init_cusps();
270
}
271
delete group;
272
}
273
}
274
275
// Predefined subgroups of SL2Z
276
277
FareySymbol::FareySymbol(PyObject* o, const is_element_group* group) {
278
init_pairing(group);
279
cusp_widths = init_cusp_widths();
280
coset = init_coset_reps();
281
generators = init_generators(group);
282
cusp_classes = init_cusp_classes();
283
for(size_t i=0; i<a.size(); i++) x.push_back(a[i]/b[i]);
284
cusps = init_cusps();
285
}
286
287
FareySymbol::~FareySymbol() {
288
}
289
290
void FareySymbol::init_pairing(const is_element_group* group) {
291
pairing = vector<int>(3, NO);
292
const mpq_class infinity(10000000);
293
pairing_max = NO;
294
if( group->is_member(SL2Z(-1, 1, -1, 0)) ) {
295
a.push_back(-1);
296
a.push_back(0);
297
b.push_back(1);
298
b.push_back(1);
299
} else {
300
a.push_back(0);
301
a.push_back(1);
302
b.push_back(1);
303
b.push_back(1);
304
}
305
check_pair(group, 0);
306
check_pair(group, 1);
307
check_pair(group, 2);
308
for(;;) {
309
int missing_pair(-1);
310
mpq_class largest_diameter(0);
311
for(size_t i=0; i<pairing.size(); i++) {
312
if( pairing[i] == NO ) {
313
if( i+1 != pairing.size() ) {
314
if( i != 0 ) {
315
mpq_class d = a[i]/b[i] - a[i-1]/b[i-1];
316
if( d > largest_diameter ) {
317
largest_diameter = d;
318
missing_pair = (int)(i);
319
}
320
} else {
321
largest_diameter = infinity;
322
missing_pair = 0;
323
}
324
} else {
325
largest_diameter = infinity;
326
missing_pair = (int)(pairing.size()-1);
327
break;
328
}
329
}
330
}
331
if( missing_pair == -1 ) {
332
break;
333
} else {
334
mpz_class A, B;
335
if( missing_pair+1 == pairing.size() ) {
336
A = a[missing_pair-1] + 1;
337
B = b[missing_pair-1] + 0;
338
} else {
339
if( missing_pair == 0 ) {
340
A = a[0] - 1;
341
B = b[0] + 0;
342
} else {
343
A = a[missing_pair-1]+a[missing_pair];
344
B = b[missing_pair-1]+b[missing_pair];
345
}
346
}
347
add_term(missing_pair, A/B);
348
}
349
check_pair(group, missing_pair);
350
check_pair(group, missing_pair+1);
351
}
352
}
353
354
void FareySymbol::add_term(const int i, const mpq_class& r) {
355
a.insert(a.begin()+i, r.get_num());
356
b.insert(b.begin()+i, r.get_den());
357
pairing.insert(pairing.begin()+i, NO);
358
}
359
360
void FareySymbol::check_pair(const is_element_group* group, const int i) {
361
if( pairing[i] == NO ) {
362
std::vector<int> even(pairing), odd(pairing);
363
even[i] = EVEN;
364
odd [i] = ODD;
365
SL2Z A = pairing_matrix(even, i);
366
SL2Z B = pairing_matrix(odd , i);
367
if( group->is_member(A) or group->is_member(-A) ) {
368
pairing[i] = EVEN;
369
return;
370
} else if( group->is_member(B) or group->is_member(-B) ) {
371
pairing[i] = ODD;
372
return;
373
}
374
}
375
if( pairing[i] == NO ) {
376
for(size_t j=0; j<pairing.size(); j++) {
377
if( pairing[j] == NO and i != j ) {
378
vector<int> p(pairing);
379
p[i] = pairing_max+1;
380
p[j] = pairing_max+1;
381
SL2Z C = pairing_matrix(p, i);
382
if( group->is_member(C) or group->is_member(-C) ) {
383
pairing_max++;
384
pairing[i] = pairing_max;
385
pairing[j] = pairing_max;
386
return;
387
}
388
}
389
}
390
}
391
}
392
393
SL2Z FareySymbol::pairing_matrix(const vector<int>& p, const size_t i) const {
394
mpz_class ai, ai1, bi, bi1, aj, aj1, bj, bj1;
395
if( i == 0 ) {
396
ai = -1; bi = 0; ai1 = a[0], bi1 = b[0];
397
} else if( i+1 == p.size() ) {
398
ai = a[i-1]; bi = b[i-1]; ai1 = 1; bi1 = 0;
399
} else {
400
ai = a[i-1]; bi = b[i-1]; ai1 = a[i]; bi1 = b[i];
401
}
402
if( p[i] == NO ) {
403
throw(string(__FUNCTION__)+string(": error"));
404
} else if( p[i] == EVEN ) {
405
return SL2Z(ai1*bi1+ai*bi, -ai*ai-ai1*ai1,
406
bi*bi+bi1*bi1, -ai1*bi1-ai*bi);
407
} else if( p[i] == ODD ) {
408
return SL2Z(ai1*bi1+ai*bi1+ai*bi, -ai*ai-ai*ai1-ai1*ai1,
409
bi*bi+bi*bi1+bi1*bi1, -ai1*bi1-ai1*bi-ai*bi);
410
} else if( p[i] > NO ) {
411
const size_t j = paired_side(p, i);
412
if( j == 0 ) {
413
aj = -1; bj = 0; aj1 = a[0]; bj1 = b[0];
414
} else if( j == a.size() ) {
415
aj = a[j-1]; bj = b[j-1]; aj1 = 1; bj1 = 0;
416
} else {
417
aj = a[j-1]; bj = b[j-1]; aj1 = a[j]; bj1 = b[j];
418
}
419
return SL2Z(aj1*bi1+aj*bi, -aj*ai-aj1*ai1,
420
bj*bi+bj1*bi1, -ai1*bj1-ai*bj);
421
}
422
return SL2Z::E;
423
}
424
425
SL2Z FareySymbol::pairing_matrix(const size_t i) const {
426
return pairing_matrix(pairing, i);
427
}
428
429
size_t FareySymbol::paired_side(const vector<int>& p, const size_t n) const {
430
if( p[n] == EVEN or p[n] == ODD ) {
431
return n;
432
} else if( p[n] > NO ) {
433
vector<int>::const_iterator i = find(p.begin(), p.end(), p[n]);
434
if( i-p.begin() != n ) {
435
return i-p.begin();
436
} else {
437
vector<int>::const_iterator j = find(i+1, p.end(), p[n]);
438
return j-p.begin();
439
}
440
}
441
throw(string(__FUNCTION__)+string(": error"));
442
return 0;
443
}
444
445
vector<SL2Z> FareySymbol::init_generators(const is_element_group *group) const {
446
const SL2Z I(-1, 0, 0, -1);
447
vector<SL2Z> gen;
448
vector<int> p;
449
for(size_t i=0; i<pairing.size(); i++) {
450
if( find(p.begin(), p.end(), pairing[i]) == p.end() ) {
451
SL2Z m = pairing_matrix(i);
452
if( not group->is_member(m) ) m = I*m;
453
if( pairing[i] == ODD and group->is_member(I) ) m = I*m;
454
gen.push_back(m);
455
if( pairing[i] > NO ) p.push_back(pairing[i]);
456
}
457
}
458
if( nu2() == 0 and nu3() == 0 and group->is_member(I) ) gen.push_back(I);
459
return gen;
460
}
461
462
vector<mpq_class> FareySymbol::init_cusp_widths() const {
463
static const mpq_class one_half(1, 2);
464
vector<mpz_class> A(a), B(b);
465
A.push_back(1);
466
B.push_back(0);
467
vector<mpq_class> w(A.size(), 0);
468
for(size_t i=0; i<w.size(); i++) {
469
size_t im = (i==0 ? A.size()-1 : i-1);
470
size_t ip = (i+1==A.size() ? 0 : i+1);
471
w[i] = abs(A[im]*B[ip]-A[ip]*B[im]);
472
if( pairing[i ] == ODD ) w[i] += one_half;
473
if( pairing[ip] == ODD ) w[i] += one_half;
474
}
475
return w;
476
}
477
478
vector<SL2Z> FareySymbol::init_coset_reps() const {
479
static const mpq_class one_half(1, 2);
480
vector<mpz_class> A(a), B(b);
481
A.insert(A.begin(), -1);
482
B.insert(B.begin(), 0);
483
vector<mpq_class> cw(cusp_widths);
484
rotate(cw.begin(), cw.end()-1, cw.end());
485
vector<int> p(pairing);
486
rotate(p.begin(), p.end()-1, p.end());
487
vector<SL2Z> reps;
488
for(size_t i=0; i<p.size(); i++) {
489
size_t j = (i+1) % p.size();
490
mpz_class c(A[j]), d(B[j]);
491
if( d == 0 ) c = 1;
492
mpq_class upper_bound(cw[i]);
493
if( p[i] == ODD ) upper_bound += one_half;
494
if( p[j] == ODD ) upper_bound -= one_half;
495
for(size_t k=0; k<upper_bound; k++) {
496
reps.push_back(SL2Z(1, -(int)(k), 0, 1)/SL2Z(-A[i], c, -B[i], d));
497
}
498
}
499
return reps;
500
}
501
502
// init cusp classes is a class of the pairing alone !!!
503
504
vector<int> FareySymbol::init_cusp_classes() const {
505
vector<int> c(pairing.size(), 0);
506
int cusp_class(1);
507
for(size_t m=0; m<c.size(); m++) {
508
if( c[m] != 0 ) {
509
continue;
510
}
511
c[m] = cusp_class;
512
size_t i(m), I, J;
513
for(;;) {
514
if( pairing[i] == NO ) {
515
I = i;
516
J = (i==0? pairing.size()-1 : (i-1)%c.size());
517
} else {
518
I = (i+1)%c.size();
519
J = I;
520
}
521
if( pairing[I] == ODD or pairing[I] == EVEN ) {
522
if( c[I] == cusp_class ) {
523
cusp_class++;
524
break;
525
}
526
c[J] = cusp_class;
527
i = J;
528
continue;
529
} else if( pairing[I] > NO ) {
530
size_t j;
531
for(size_t k=0; k<c.size(); k++) {
532
if( pairing[k] == pairing[I] and k != I ) j = k;
533
}
534
if( I != i ) {
535
if( c[j] == cusp_class ) {
536
cusp_class++;
537
break;
538
}
539
c[j] = cusp_class;
540
i = j;
541
continue;
542
} else {
543
if( c[j-1] == cusp_class ) {
544
cusp_class++;
545
break;
546
}
547
c[j-1] = cusp_class;
548
i = j-1;
549
continue;
550
}
551
}
552
}
553
}
554
return c;
555
}
556
557
vector<mpq_class> FareySymbol::init_cusps() const {
558
// initialize cusps by identifying fractions using the cusp_class number
559
vector<mpq_class> c;
560
for(int i=1; i<=number_of_cusps(); i++) {
561
for(size_t j=0; j<cusp_classes.size(); j++) {
562
if( cusp_classes[j] == i and cusp_classes[j] != cusp_classes.back() ) {
563
c.push_back(x[j]);
564
break;
565
}
566
}
567
}
568
// width of cusp at infinity
569
mpq_class W(0);
570
for(size_t i=0; i<cusp_classes.size(); i++) {
571
if( cusp_classes[i] == cusp_classes.back() ) W += cusp_widths[i];
572
}
573
// shift negative cusps to positve
574
for(size_t i=0; i<c.size(); i++) while(c[i]<0) c[i] += W;
575
sort(c.begin(), c.end());
576
return c;
577
}
578
579
size_t FareySymbol::nu2() const {
580
return count(pairing.begin(), pairing.end(), EVEN);
581
}
582
583
size_t FareySymbol::nu3() const {
584
return count(pairing.begin(), pairing.end(), ODD);
585
}
586
587
size_t FareySymbol::rank_pi() const {
588
if( index() == 2 ) return 1;
589
return count_if(pairing.begin(), pairing.end(),
590
bind2nd(greater<int>(), 0))/2;
591
}
592
593
size_t FareySymbol::number_of_cusps() const {
594
return size_t(*max_element(cusp_classes.begin(), cusp_classes.end()));
595
}
596
597
size_t FareySymbol::genus() const {
598
return (rank_pi()-number_of_cusps()+1)/2;
599
}
600
601
size_t FareySymbol::level() const {
602
if( index() == 2 ) return 2;
603
vector<mpz_class> A(a), B(b);
604
A.push_back(1);
605
B.push_back(0);
606
vector<mpz_class> width;
607
for(size_t i=1; i<=number_of_cusps(); i++) {
608
mpq_class cusp_width(0);
609
for(size_t j=0; j<cusp_widths.size(); j++) {
610
if( cusp_classes[j] == i ) {
611
cusp_width += cusp_widths[j];
612
}
613
}
614
width.push_back(cusp_width.get_num());
615
}
616
return lcm(width).get_ui();
617
}
618
619
//--- communication with sage ------------------------------------------------
620
621
size_t FareySymbol::index() const {
622
return coset.size();
623
}
624
625
PyObject* FareySymbol::get_coset() const {
626
PyObject* coset_list = PyList_New(coset.size());
627
for(size_t i=0; i<coset.size(); i++) {
628
PyObject* m = convert_to_SL2Z(coset[i]);
629
PyList_SetItem(coset_list, i, m);
630
}
631
return coset_list;
632
}
633
634
PyObject* FareySymbol::get_generators() const {
635
PyObject* generators_list = PyList_New(generators.size());
636
for(size_t i=0; i<generators.size(); i++) {
637
PyObject* m = convert_to_SL2Z(generators[i]);
638
PyList_SetItem(generators_list, i, m);
639
}
640
return generators_list;
641
}
642
643
PyObject* FareySymbol::get_cusp_widths() const {
644
PyObject* cusp_widths_list = PyList_New(cusp_widths.size());
645
for(size_t i=0; i<cusp_widths.size(); i++) {
646
PyObject* m = convert_to_rational(cusp_widths[i]);
647
PyList_SetItem(cusp_widths_list, i, m);
648
}
649
return cusp_widths_list;
650
}
651
652
PyObject* FareySymbol::get_cusps() const {
653
PyObject* cusps_list = PyList_New(cusps.size());
654
for(size_t i=0; i<cusps.size(); i++) {
655
PyObject* m = convert_to_cusp(cusps[i]);
656
PyList_SetItem(cusps_list, i, m);
657
}
658
return cusps_list;
659
}
660
661
PyObject* FareySymbol::get_fractions() const {
662
PyObject* x_list = PyList_New(x.size());
663
for(size_t i=0; i<x.size(); i++) {
664
PyObject* m = convert_to_rational(x[i]);
665
PyList_SetItem(x_list, i, m);
666
}
667
return x_list;
668
}
669
670
PyObject* FareySymbol::get_pairings() const {
671
PyObject* pairing_list = PyList_New(pairing.size());
672
for(size_t i=0; i<pairing.size(); i++) {
673
PyObject* m = PyInt_FromLong(long(pairing[i]));
674
PyList_SetItem(pairing_list, i, m);
675
}
676
return pairing_list;
677
}
678
679
PyObject* FareySymbol::get_paired_sides() const {
680
vector<int> p;
681
for(size_t i=0; i<pairing.size(); i++) {
682
if( pairing[i] > NO and
683
p.end() == find(p.begin(), p.end(), pairing[i]) ) {
684
p.push_back(pairing[i]);
685
}
686
}
687
sort(p.begin(), p.end());
688
PyObject* pairing_list = PyList_New(p.size());
689
for(vector<int>::const_iterator i=p.begin(); i!=p.end(); i++) {
690
vector<int>::const_iterator j = find(pairing.begin(), pairing.end(), *i);
691
vector<int>::const_iterator k = find(j+1, pairing.end(), *i);
692
PyObject* J = PyInt_FromLong(long(j-pairing.begin()));
693
PyObject* K = PyInt_FromLong(long(k-pairing.begin()));
694
PyObject* tuple = PyTuple_New(2);
695
PyTuple_SetItem(tuple, 0, J);
696
PyTuple_SetItem(tuple, 1, K);
697
PyList_SetItem(pairing_list, i-p.begin(), tuple);
698
}
699
return pairing_list;
700
}
701
702
PyObject* FareySymbol::get_pairing_matrices() const {
703
PyObject* pairing_matrix_list = PyList_New(pairing.size());
704
for(size_t i=0; i<pairing.size(); i++) {
705
PyObject* pm = convert_to_SL2Z(pairing_matrix(i));
706
PyList_SetItem(pairing_matrix_list, i, pm);
707
}
708
return pairing_matrix_list;
709
}
710
711
PyObject* FareySymbol::dumps() const {
712
ostringstream os(ostringstream::out|ostringstream::binary);
713
os << (*this);
714
PyObject* d = PyString_FromString(os.str().c_str());
715
return d;
716
}
717
718
719