Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/combinat/iet/reduced.py
4069 views
1
r"""
2
Reduced permutations
3
4
A reduced (generalized) permutation is better suited to study strata of Abelian
5
(or quadratic) holomorphic forms on Riemann surfaces. The Rauzy diagram is an
6
invariant of such a component. Corentin Boissy proved the identification of
7
Rauzy diagrams with connected components of stratas. But the geometry of the
8
diagram and the relation with the strata is not yet totally understood.
9
10
AUTHORS:
11
12
- Vincent Delecroix (2000-09-29): initial version
13
14
TESTS::
15
16
sage: from sage.combinat.iet.reduced import ReducedPermutationIET
17
sage: ReducedPermutationIET([['a','b'],['b','a']])
18
a b
19
b a
20
sage: ReducedPermutationIET([[1,2,3],[3,1,2]])
21
1 2 3
22
3 1 2
23
sage: from sage.combinat.iet.reduced import ReducedPermutationLI
24
sage: ReducedPermutationLI([[1,1],[2,2,3,3,4,4]])
25
1 1
26
2 2 3 3 4 4
27
sage: ReducedPermutationLI([['a','a','b','b','c','c'],['d','d']])
28
a a b b c c
29
d d
30
sage: from sage.combinat.iet.reduced import FlippedReducedPermutationIET
31
sage: FlippedReducedPermutationIET([[1,2,3],[3,2,1]],flips=[1,2])
32
-1 -2 3
33
3 -2 -1
34
sage: FlippedReducedPermutationIET([['a','b','c'],['b','c','a']],flips='b')
35
a -b c
36
-b c a
37
sage: from sage.combinat.iet.reduced import FlippedReducedPermutationLI
38
sage: FlippedReducedPermutationLI([[1,1],[2,2,3,3,4,4]], flips=[1,4])
39
-1 -1
40
2 2 3 3 -4 -4
41
sage: FlippedReducedPermutationLI([['a','a','b','b'],['c','c']],flips='ac')
42
-a -a b b
43
-c -c
44
sage: from sage.combinat.iet.reduced import ReducedRauzyDiagram
45
sage: p = ReducedPermutationIET([[1,2,3],[3,2,1]])
46
sage: d = ReducedRauzyDiagram(p)
47
"""
48
#*****************************************************************************
49
# Copyright (C) 2008 Vincent Delecroix <[email protected]>
50
#
51
# Distributed under the terms of the GNU General Public License (GPL)
52
# http://www.gnu.org/licenses/
53
#*****************************************************************************
54
55
from sage.structure.sage_object import SageObject
56
57
from copy import copy
58
59
from sage.combinat.words.alphabet import Alphabet
60
from sage.rings.integer import Integer
61
62
from template import PermutationIET, PermutationLI # permutations
63
from template import FlippedPermutationIET, FlippedPermutationLI # flipped permutations
64
from template import twin_list_iet, twin_list_li
65
from template import RauzyDiagram, FlippedRauzyDiagram
66
67
from template import interval_conversion, side_conversion
68
69
class ReducedPermutation(SageObject) :
70
r"""
71
Template for reduced objects.
72
73
.. warning::
74
75
Internal class! Do not use directly!
76
77
INPUT:
78
79
- ``intervals`` - a list of two list of labels
80
81
- ``alphabet`` - (default: None) any object that can be used to initialize an Alphabet or None. In this latter case, the letter of the intervals are used to generate one.
82
"""
83
def __init__(self,intervals=None,alphabet=None):
84
r"""
85
TESTS::
86
87
sage: from sage.combinat.iet.reduced import ReducedPermutationIET
88
sage: p = ReducedPermutationIET()
89
sage: loads(dumps(p)) == p
90
True
91
sage: p = ReducedPermutationIET([['a','b'],['b','a']])
92
sage: loads(dumps(p)) == p
93
True
94
sage: from sage.combinat.iet.reduced import ReducedPermutationLI
95
sage: p = ReducedPermutationLI()
96
sage: loads(dumps(p)) == p
97
True
98
sage: p = ReducedPermutationLI([['a','a'],['b','b']])
99
sage: loads(dumps(p)) == p
100
True
101
"""
102
self._hash = None
103
104
if intervals is None:
105
self._twin = [[],[]]
106
self._alphabet = alphabet
107
108
else:
109
self._init_twin(intervals)
110
111
if alphabet is None:
112
self._init_alphabet(intervals)
113
else:
114
alphabet = Alphabet(alphabet)
115
if alphabet.cardinality() < len(self):
116
raise TypeError("The alphabet is too short")
117
self._alphabet = alphabet
118
119
def __len__(self):
120
r"""
121
TESTS::
122
123
sage: p = iet.Permutation('a b','b a',reduced=True)
124
sage: len(p)
125
2
126
sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True)
127
sage: len(p)
128
3
129
sage: p = iet.GeneralizedPermutation('a a','b b c c',reduced=True)
130
sage: len(p)
131
3
132
"""
133
return (len(self._twin[0]) + len(self._twin[1])) / 2
134
135
def length_top(self):
136
r"""
137
Returns the number of intervals in the top segment.
138
139
OUTPUT:
140
141
integer -- the length of the top segment
142
143
EXAMPLES::
144
145
sage: p = iet.Permutation('a b c','c b a')
146
sage: p.length_top()
147
3
148
sage: p = iet.GeneralizedPermutation('a a b','c d c b d')
149
sage: p.length_top()
150
3
151
sage: p = iet.GeneralizedPermutation('a b c b d c d', 'e a e')
152
sage: p.length_top()
153
7
154
"""
155
return len(self._twin[0])
156
157
def length_bottom(self):
158
r"""
159
Returns the number of intervals in the bottom segment.
160
161
OUTPUT:
162
163
integer -- the length of the bottom segment
164
165
EXAMPLES::
166
167
sage: p = iet.Permutation('a b c','c b a')
168
sage: p.length_bottom()
169
3
170
sage: p = iet.GeneralizedPermutation('a a b','c d c b d')
171
sage: p.length_bottom()
172
5
173
"""
174
return len(self._twin[1])
175
176
def length(self, interval=None):
177
r"""
178
Returns the 2-uple of lengths.
179
180
p.length() is identical to (p.length_top(), p.length_bottom())
181
If an interval is specified, it returns the length of the specified
182
interval.
183
184
INPUT:
185
186
- ``interval`` - None, 'top' (or 't' or 0) or 'bottom' (or 'b' or 1)
187
188
OUTPUT:
189
190
integer or 2-uple of integers -- the corresponding lengths
191
192
EXAMPLES::
193
194
sage: p = iet.Permutation('a b c','c b a')
195
sage: p.length()
196
(3, 3)
197
sage: p = iet.GeneralizedPermutation('a a b','c d c b d')
198
sage: p.length()
199
(3, 5)
200
"""
201
if interval is None :
202
return len(self._twin[0]),len(self._twin[1])
203
else :
204
interval = interval_conversion(interval)
205
return len(self._twin[interval])
206
207
def __getitem__(self,i):
208
r"""
209
TESTS::
210
211
sage: p = iet.Permutation('a b', 'b a', reduced=True)
212
sage: print p[0]
213
['a', 'b']
214
sage: print p[1]
215
['b', 'a']
216
sage: p.alphabet([0,1])
217
sage: print p[0]
218
[0, 1]
219
sage: print p[1]
220
[1, 0]
221
"""
222
return self.list().__getitem__(i)
223
224
def __copy__(self) :
225
r"""
226
Returns a copy of self.
227
228
EXAMPLES::
229
230
sage: p = iet.Permutation('a b c', 'c b a', reduced=True)
231
sage: q = copy(p)
232
sage: p == q
233
True
234
sage: p is q
235
False
236
sage: p = iet.GeneralizedPermutation('a b b','c c a', reduced=True)
237
sage: q = copy(p)
238
sage: p == q
239
True
240
sage: p is q
241
False
242
"""
243
q = self.__class__()
244
245
q._twin = [self._twin[0][:], self._twin[1][:]]
246
q._alphabet = self._alphabet
247
q._repr_type = self._repr_type
248
q._repr_options = self._repr_options
249
250
return q
251
252
def erase_letter(self, letter):
253
r"""
254
Erases a letter.
255
256
INPUT:
257
258
- ``letter`` - a letter which is a label of an interval of self
259
260
EXAMPLES:
261
262
::
263
264
sage: p = iet.Permutation('a b c','c b a')
265
sage: p.erase_letter('a')
266
b c
267
c b
268
269
::
270
271
sage: p = iet.GeneralizedPermutation('a b b','c c a')
272
sage: p.erase_letter('a')
273
b b
274
c c
275
"""
276
l = self.list()
277
278
del l[0][l[0].index(letter)]
279
del l[1][l[1].index(letter)]
280
281
return self.__class__(l)
282
283
def right_rauzy_move(self, winner):
284
r"""
285
Performs a Rauzy move on the right.
286
287
EXAMPLES:
288
289
::
290
291
sage: p = iet.Permutation('a b c','c b a',reduced=True)
292
sage: p.right_rauzy_move(0)
293
a b c
294
c a b
295
sage: p.right_rauzy_move(1)
296
a b c
297
b c a
298
299
::
300
301
sage: p = iet.GeneralizedPermutation('a a','b b c c',reduced=True)
302
sage: p.right_rauzy_move(0)
303
a b b
304
c c a
305
"""
306
winner = interval_conversion(winner)
307
308
result = copy(self)
309
310
loser_to = result._get_loser_to(winner)
311
# beware here, loser_to can contain 2 or 3 items
312
# (depending on the presence of flip)
313
314
result._twin_rauzy_move(winner, loser_to)
315
316
return result
317
318
def left_rauzy_move(self, winner):
319
r"""
320
Performs a Rauzy move on the left.
321
322
EXAMPLES:
323
324
::
325
326
sage: p = iet.Permutation('a b c','c b a',reduced=True)
327
sage: p.left_rauzy_move(0)
328
a b c
329
b c a
330
sage: p.right_rauzy_move(1)
331
a b c
332
b c a
333
334
::
335
336
sage: p = iet.GeneralizedPermutation('a a','b b c c',reduced=True)
337
sage: p.left_rauzy_move(0)
338
a a b
339
b c c
340
"""
341
winner = interval_conversion(winner)
342
343
result = copy(self)
344
result._reversed()
345
result = result.right_rauzy_move(winner)
346
result._reversed()
347
return result
348
349
_RP = ReducedPermutation
350
351
def alphabetized_atwin(twin, alphabet):
352
"""
353
Alphabetization of a twin of iet.
354
355
TESTS::
356
357
sage: from sage.combinat.iet.reduced import alphabetized_atwin
358
359
::
360
361
sage: twin = [[0,1],[0,1]]
362
sage: alphabet = Alphabet("ab")
363
sage: alphabetized_atwin(twin, alphabet)
364
[['a', 'b'], ['a', 'b']]
365
366
::
367
368
sage: twin = [[1,0],[1,0]]
369
sage: alphabet = Alphabet([0,1])
370
sage: alphabetized_atwin(twin, alphabet)
371
[[0, 1], [1, 0]]
372
373
::
374
375
sage: twin = [[1,2,3,0],[3,0,1,2]]
376
sage: alphabet = Alphabet("abcd")
377
sage: alphabetized_atwin(twin,alphabet)
378
[['a', 'b', 'c', 'd'], ['d', 'a', 'b', 'c']]
379
"""
380
l = [[],[]]
381
382
l[0] = map(lambda x: alphabet.unrank(x), range(len(twin[0])))
383
l[1] = map(lambda x: alphabet.unrank(x), twin[1])
384
385
return l
386
387
def ReducedPermutationsIET_iterator(
388
nintervals=None,
389
irreducible=True,
390
alphabet=None):
391
r"""
392
Returns an iterator over reduced permutations
393
394
INPUT:
395
396
- ``nintervals`` - integer or None
397
398
- ``irreducible`` - boolean
399
400
- ``alphabet`` - something that should be converted to an alphabet
401
of at least nintervals letters
402
403
TESTS::
404
405
sage: for p in iet.Permutations_iterator(3,reduced=True,alphabet="abc"):
406
... print p #indirect doctest
407
a b c
408
b c a
409
a b c
410
c a b
411
a b c
412
c b a
413
"""
414
from itertools import imap,ifilter
415
from sage.combinat.permutation import Permutations
416
417
if irreducible is False:
418
if nintervals is None:
419
raise NotImplementedError, "choose a number of intervals"
420
else:
421
assert(isinstance(nintervals,(int,Integer)))
422
assert(nintervals > 0)
423
424
a0 = range(1,nintervals+1)
425
f = lambda x: ReducedPermutationIET([a0,list(x)],
426
alphabet=alphabet)
427
return imap(f, Permutations(nintervals))
428
else:
429
return ifilter(lambda x: x.is_irreducible(),
430
ReducedPermutationsIET_iterator(nintervals,False,alphabet))
431
432
class ReducedPermutationIET(ReducedPermutation, PermutationIET):
433
"""
434
Reduced permutation from iet
435
436
Permutation from iet without numerotation of intervals. For initialization,
437
you should use GeneralizedPermutation which is the class factory for all
438
permutation types.
439
440
EXAMPLES:
441
442
Equality testing (no equality of letters but just of ordering)::
443
444
sage: p = iet.Permutation('a b c', 'c b a', reduced = True)
445
sage: q = iet.Permutation('p q r', 'r q p', reduced = True)
446
sage: p == q
447
True
448
449
Reducibility testing::
450
451
sage: p = iet.Permutation('a b c', 'c b a', reduced = True)
452
sage: p.is_irreducible()
453
True
454
455
::
456
457
sage: q = iet.Permutation('a b c d', 'b a d c', reduced = True)
458
sage: q.is_irreducible()
459
False
460
461
462
Rauzy movability and Rauzy move::
463
464
sage: p = iet.Permutation('a b c', 'c b a', reduced = True)
465
sage: p.has_rauzy_move(1)
466
True
467
sage: print p.rauzy_move(1)
468
a b c
469
b c a
470
471
Rauzy diagrams::
472
473
sage: p = iet.Permutation('a b c d', 'd a b c')
474
sage: p_red = iet.Permutation('a b c d', 'd a b c', reduced = True)
475
sage: d = p.rauzy_diagram()
476
sage: d_red = p_red.rauzy_diagram()
477
sage: p.rauzy_move(0) in d
478
True
479
sage: print d.cardinality(), d_red.cardinality()
480
12 6
481
"""
482
def _init_twin(self, a):
483
r"""
484
Initializes the _twin attribute
485
486
TESTS::
487
488
sage: p = iet.Permutation('a b','b a',reduced=True) #indirect doctest
489
sage: p._twin
490
[[1, 0], [1, 0]]
491
"""
492
self._twin = twin_list_iet(a)
493
494
def list(self):
495
r"""
496
Returns a list of two list that represents the permutation.
497
498
EXAMPLES::
499
500
sage: p = iet.GeneralizedPermutation('a b','b a',reduced=True)
501
sage: p.list() == [p[0], p[1]]
502
True
503
sage: p.list() == [['a', 'b'], ['b', 'a']]
504
True
505
506
::
507
508
sage: p = iet.GeneralizedPermutation('a b c', 'b c a',reduced=True)
509
sage: iet.GeneralizedPermutation(p.list(),reduced=True) == p
510
True
511
"""
512
a0 = map(self._alphabet.unrank, range(0,len(self)))
513
a1 = map(self._alphabet.unrank, self._twin[1])
514
return [a0,a1]
515
516
def is_identity(self):
517
r"""
518
Returns True if self is the identity.
519
520
EXAMPLES::
521
522
sage: iet.Permutation("a b","a b",reduced=True).is_identity()
523
True
524
sage: iet.Permutation("a b","b a",reduced=True).is_identity()
525
False
526
"""
527
for i in range(len(self)):
528
if self._twin[0][i] != i:
529
return False
530
return True
531
532
def __hash__(self):
533
r"""
534
Returns a hash value (does not depends of the alphabet).
535
536
TESTS::
537
sage: p = iet.Permutation([1,2],[1,2], reduced=True)
538
sage: q = iet.Permutation([1,2],[2,1], reduced=True)
539
sage: r = iet.Permutation([2,1],[1,2], reduced=True)
540
sage: hash(p) == hash(q)
541
False
542
sage: hash(q) == hash(r)
543
True
544
"""
545
if self._hash is None:
546
self._hash = hash(tuple(self._twin[0]))
547
return self._hash
548
549
def __cmp__(self, other):
550
r"""
551
Defines a natural lexicographic order.
552
553
TESTS::
554
555
sage: p = iet.GeneralizedPermutation('a b','a b',reduced=True)
556
sage: q = copy(p)
557
sage: q.alphabet([0,1])
558
sage: p == q
559
True
560
sage: p0 = iet.GeneralizedPermutation('a b', 'a b', reduced=True)
561
sage: p1 = iet.GeneralizedPermutation('a b', 'b a', reduced=True)
562
sage: p0 < p1 and p1 > p0
563
True
564
sage: q0 = iet.GeneralizedPermutation('a b c','a b c',reduced=True)
565
sage: q1 = iet.GeneralizedPermutation('a b c','a c b',reduced=True)
566
sage: q2 = iet.GeneralizedPermutation('a b c','b a c',reduced=True)
567
sage: q3 = iet.GeneralizedPermutation('a b c','b c a',reduced=True)
568
sage: q4 = iet.GeneralizedPermutation('a b c','c a b',reduced=True)
569
sage: q5 = iet.GeneralizedPermutation('a b c','c b a',reduced=True)
570
sage: p0 < q0 and q0 > p0 and p1 < q0 and q0 > p1
571
True
572
sage: q0 < q1 and q1 > q0
573
True
574
sage: q1 < q2 and q2 > q1
575
True
576
sage: q2 < q3 and q3 > q2
577
True
578
sage: q3 < q4 and q4 > q3
579
True
580
sage: q4 < q5 and q5 > q4
581
True
582
"""
583
if type(self) != type(other):
584
raise ValueError, "Permutations must be of the same type"
585
586
if len(self) > len(other):
587
return 1
588
elif len(self) < len(other):
589
return -1
590
591
n = len(self)
592
j = 0
593
while (j < n and self._twin[1][j] == other._twin[1][j]):
594
j += 1
595
596
if j != n:
597
if self._twin[1][j] > other._twin[1][j]: return 1
598
else: return -1
599
600
return 0
601
602
def _reversed(self):
603
r"""
604
Reverses the permutation.
605
606
EXAMPLES:
607
608
::
609
610
sage: p = iet.Permutation('a b c','c a b',reduced=True)
611
sage: p
612
a b c
613
c a b
614
sage: p._reversed()
615
sage: p
616
a b c
617
b c a
618
619
::
620
621
sage: p = iet.Permutation('a b c d','d a b c',reduced=True)
622
sage: p
623
a b c d
624
d a b c
625
sage: p._reversed()
626
sage: p
627
a b c d
628
b c d a
629
"""
630
tmp = [self._twin[0][:], self._twin[1][:]]
631
632
n = self.length_top()
633
for i in (0,1):
634
for j in range(n):
635
tmp[i][n- 1 - j] = n - 1 - self._twin[i][j]
636
637
self._twin = tmp
638
639
def _inversed(self):
640
r"""
641
Inverses the permutation.
642
643
EXAMPLES:
644
645
::
646
647
sage: p = iet.Permutation('a b c','c a b',reduced=True)
648
sage: p
649
a b c
650
c a b
651
sage: p._inversed()
652
sage: p
653
a b c
654
b c a
655
656
::
657
658
sage: p = iet.Permutation('a b c d','d a b c',reduced=True)
659
sage: p
660
a b c d
661
d a b c
662
sage: p._inversed()
663
sage: p
664
a b c d
665
b c d a
666
"""
667
self._twin = [self._twin[1], self._twin[0]]
668
669
def has_rauzy_move(self, winner, side='right'):
670
r"""
671
Tests if the permutation is rauzy_movable on the left.
672
673
EXAMPLES:
674
675
::
676
677
sage: p = iet.Permutation('a b c','a c b',reduced=True)
678
sage: p.has_rauzy_move(0,'right')
679
True
680
sage: p.has_rauzy_move(0,'left')
681
False
682
sage: p.has_rauzy_move(1,'right')
683
True
684
sage: p.has_rauzy_move(1,'left')
685
False
686
687
::
688
689
sage: p = iet.Permutation('a b c d','c a b d',reduced=True)
690
sage: p.has_rauzy_move(0,'right')
691
False
692
sage: p.has_rauzy_move(0,'left')
693
True
694
sage: p.has_rauzy_move(1,'right')
695
False
696
sage: p.has_rauzy_move(1,'left')
697
True
698
"""
699
side = side_conversion(side)
700
winner = interval_conversion(winner)
701
702
return self._twin[winner][side] % len(self) != side % len(self)
703
704
def rauzy_move_relabel(self, winner, side='right'):
705
r"""
706
Returns the relabelization obtained from this move.
707
708
EXAMPLE::
709
710
sage: p = iet.Permutation('a b c d','d c b a')
711
sage: q = p.reduced()
712
sage: p_t = p.rauzy_move('t')
713
sage: q_t = q.rauzy_move('t')
714
sage: s_t = q.rauzy_move_relabel('t')
715
sage: print s_t
716
WordMorphism: a->a, b->b, c->c, d->d
717
sage: map(s_t, p_t[0]) == map(Word, q_t[0])
718
True
719
sage: map(s_t, p_t[1]) == map(Word, q_t[1])
720
True
721
sage: p_b = p.rauzy_move('b')
722
sage: q_b = q.rauzy_move('b')
723
sage: s_b = q.rauzy_move_relabel('b')
724
sage: print s_b
725
WordMorphism: a->a, b->d, c->b, d->c
726
sage: map(s_b, q_b[0]) == map(Word, p_b[0])
727
True
728
sage: map(s_b, q_b[1]) == map(Word, p_b[1])
729
True
730
"""
731
from sage.combinat.iet.labelled import LabelledPermutationIET
732
from sage.combinat.words.morphism import WordMorphism
733
734
winner = interval_conversion(winner)
735
side = side_conversion(side)
736
737
p = LabelledPermutationIET(self.list())
738
739
l0_q = p.rauzy_move(winner, side).list()[0]
740
741
d = dict([(self._alphabet[i],l0_q[i]) for i in range(len(self))])
742
743
return WordMorphism(d)
744
745
def _get_loser_to(self, winner) :
746
r"""
747
This function return the position of the future loser position.
748
749
TESTS:
750
751
::
752
753
sage: p = iet.Permutation('a b c','c b a',reduced=True)
754
sage: p._get_loser_to(0)
755
(1, 1)
756
sage: p._get_loser_to(1)
757
(0, 1)
758
759
::
760
761
sage: p = iet.Permutation('a b c','c a b',reduced=True)
762
sage: p._get_loser_to(0)
763
(1, 1)
764
sage: p._get_loser_to(1)
765
(0, 2)
766
767
::
768
769
sage: p = iet.Permutation('a b c','b c a',reduced=True)
770
sage: p._get_loser_to(0)
771
(1, 2)
772
sage: p._get_loser_to(1)
773
(0, 1)
774
"""
775
return (1-winner, self._twin[winner][-1]+1)
776
777
def _twin_rauzy_move(self, winner_interval, loser_to) :
778
r"""
779
Do a Rauzy move for this choice of winner.
780
781
TESTS::
782
783
sage: p = iet.Permutation('a b','b a',reduced=True)
784
sage: p.rauzy_move(0) == p #indirect doctest
785
True
786
sage: p.rauzy_move(1) == p #indirect doctest
787
True
788
"""
789
loser_interval = 1 - winner_interval
790
791
loser_twin_interval = winner_interval
792
loser_twin_position = self._twin[loser_interval][-1]
793
794
loser_interval_to, loser_position_to = loser_to
795
796
# move the loser
797
del self._twin[loser_interval][-1]
798
self._twin[loser_interval_to].insert(loser_position_to, loser_twin_position)
799
self._twin[loser_twin_interval][loser_twin_position] = loser_position_to
800
801
# increment the twins in the winner interval
802
for j in range(loser_position_to + 1, self.length(loser_interval_to)) :
803
self._twin[winner_interval][self._twin[loser_interval_to][j]] += 1
804
805
def rauzy_diagram(self, **kargs):
806
r"""
807
Returns the associated Rauzy diagram.
808
809
OUTPUT:
810
811
A Rauzy diagram
812
813
EXAMPLES:
814
815
::
816
817
sage: p = iet.Permutation('a b c d', 'd a b c',reduced=True)
818
sage: d = p.rauzy_diagram()
819
sage: p.rauzy_move(0) in d
820
True
821
sage: p.rauzy_move(1) in d
822
True
823
824
For more information, try help RauzyDiagram
825
"""
826
return ReducedRauzyDiagram(self, **kargs)
827
828
def alphabetized_qtwin(twin, alphabet):
829
"""
830
Alphabetization of a qtwin.
831
832
TESTS::
833
834
sage: from sage.combinat.iet.reduced import alphabetized_qtwin
835
836
::
837
838
sage: twin = [[(1,0),(1,1)],[(0,0),(0,1)]]
839
sage: alphabet = Alphabet("ab")
840
sage: print alphabetized_qtwin(twin,alphabet)
841
[['a', 'b'], ['a', 'b']]
842
843
::
844
845
sage: twin = [[(1,1), (1,0)],[(0,1), (0,0)]]
846
sage: alphabet=Alphabet("AB")
847
sage: alphabetized_qtwin(twin,alphabet)
848
[['A', 'B'], ['B', 'A']]
849
sage: alphabet=Alphabet("BA")
850
sage: alphabetized_qtwin(twin,alphabet)
851
[['B', 'A'], ['A', 'B']]
852
853
::
854
855
sage: twin = [[(0,1),(0,0)],[(1,1),(1,0)]]
856
sage: alphabet=Alphabet("ab")
857
sage: print alphabetized_qtwin(twin,alphabet)
858
[['a', 'a'], ['b', 'b']]
859
860
::
861
862
sage: twin = [[(0,2),(1,1),(0,0)],[(1,2),(0,1),(1,0)]]
863
sage: alphabet=Alphabet("abc")
864
sage: print alphabetized_qtwin(twin,alphabet)
865
[['a', 'b', 'a'], ['c', 'b', 'c']]
866
"""
867
i_a = 0
868
l = [[False]*len(twin[0]),[False]*len(twin[1])]
869
# False means empty here
870
for i in range(2) :
871
for j in range(len(l[i])) :
872
if l[i][j] is False :
873
l[i][j] = alphabet[i_a]
874
l[twin[i][j][0]][twin[i][j][1]] = alphabet[i_a]
875
i_a += 1
876
return l
877
878
class ReducedPermutationLI(ReducedPermutation, PermutationLI):
879
r"""
880
Reduced quadratic (or generalized) permutation.
881
882
EXAMPLES:
883
884
Reducibility testing::
885
886
sage: p = iet.GeneralizedPermutation('a b b', 'c c a', reduced = True)
887
sage: p.is_irreducible()
888
True
889
890
::
891
892
sage: p = iet.GeneralizedPermutation('a b c a', 'b d d c', reduced = True)
893
sage: p.is_irreducible()
894
False
895
sage: test, decomposition = p.is_irreducible(return_decomposition = True)
896
sage: test
897
False
898
sage: decomposition
899
(['a'], ['c', 'a'], [], ['c'])
900
901
Rauzy movavability and Rauzy move::
902
903
sage: p = iet.GeneralizedPermutation('a b b', 'c c a', reduced = True)
904
sage: p.has_rauzy_move(0)
905
True
906
sage: p.rauzy_move(0)
907
a a b b
908
c c
909
sage: p.rauzy_move(0).has_rauzy_move(0)
910
False
911
sage: p.rauzy_move(1)
912
a b b
913
c c a
914
915
Rauzy diagrams::
916
917
sage: p_red = iet.GeneralizedPermutation('a b b', 'c c a', reduced = True)
918
sage: d_red = p_red.rauzy_diagram()
919
sage: d_red.cardinality()
920
4
921
"""
922
def _init_twin(self, a):
923
r"""
924
Initializes the _twin attribute
925
926
TESTS::
927
928
sage: p = iet.GeneralizedPermutation('a a','b b',reduced=True) #indirect doctest
929
sage: p._twin
930
[[(0, 1), (0, 0)], [(1, 1), (1, 0)]]
931
"""
932
self._twin = twin_list_li(a)
933
934
def list(self) :
935
r"""
936
The permutations as a list of two lists.
937
938
EXAMPLES::
939
940
sage: p = iet.GeneralizedPermutation('a b b', 'c c a', reduced = True)
941
sage: list(p)
942
[['a', 'b', 'b'], ['c', 'c', 'a']]
943
"""
944
return alphabetized_qtwin(self._twin, self.alphabet())
945
946
def __eq__(self, other) :
947
r"""
948
Tests equality.
949
950
Two reduced permutations are equal if they have the same order of
951
apparition of intervals. Non necessarily the same alphabet.
952
953
TESTS::
954
955
sage: p = iet.GeneralizedPermutation('a b b', 'c c a', reduced = True)
956
sage: q = iet.GeneralizedPermutation('b a a', 'c c b', reduced = True)
957
sage: r = iet.GeneralizedPermutation('t s s', 'w w t', reduced = True)
958
sage: p == q
959
True
960
sage: p == r
961
True
962
"""
963
return type(self) == type(other) and self._twin == other._twin
964
965
def __ne__(self, other) :
966
"""
967
Tests difference.
968
969
TESTS::
970
sage: p = iet.GeneralizedPermutation('a b b', 'c c a', reduced = True)
971
sage: q = iet.GeneralizedPermutation('b b a', 'c c a', reduced = True)
972
sage: r = iet.GeneralizedPermutation('i j j', 'k k i', reduced = True)
973
sage: p != q
974
True
975
sage: p != r
976
False
977
"""
978
return type(self) != type(other) or (self._twin != other._twin)
979
980
def _get_loser_to(self, winner) :
981
r"""
982
This function return the position of the future loser position.
983
984
TESTS::
985
986
sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True)
987
sage: p._get_loser_to(0)
988
(1, 1)
989
sage: p._get_loser_to(1)
990
(1, 1)
991
"""
992
loser = 1 - winner
993
994
if self._twin[winner][-1][0] == loser:
995
return (loser, self._twin[winner][-1][1] + 1)
996
else:
997
return (winner, self._twin[winner][-1][1])
998
999
def _twin_rauzy_move(self, winner_interval, loser_to) :
1000
r"""
1001
Rauzy move on the twin data
1002
1003
TESTS:
1004
1005
::
1006
1007
sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True)
1008
sage: p.rauzy_move(0) #indirect doctest
1009
a a b
1010
b c c
1011
sage: p.rauzy_move(1) #indirect doctest
1012
a a
1013
b b c c
1014
1015
::
1016
1017
sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True)
1018
sage: p.rauzy_move(0) #indirect doctest
1019
a a b
1020
b c c
1021
sage: p.rauzy_move(1) #indirect doctest
1022
a a
1023
b b c c
1024
"""
1025
loser_interval = 1 - winner_interval
1026
1027
loser_interval_to, loser_position_to = loser_to
1028
loser_twin_interval, loser_twin_position = self._twin[loser_interval][-1]
1029
1030
# increment the twins in the winner interval
1031
interval = [(self._twin[loser_interval_to][j], j) for j in range(loser_position_to, len(self._twin[loser_interval_to]))]
1032
for (i,j),k in interval : self._twin[i][j] = (loser_interval_to, k+1)
1033
1034
# prepare the loser new position in its twin
1035
self._twin[loser_twin_interval][loser_twin_position] = loser_to
1036
1037
# move the loser
1038
loser_twin = self._twin[loser_interval][-1]
1039
self._twin[loser_interval_to].insert(loser_position_to, loser_twin)
1040
del self._twin[loser_interval][-1]
1041
1042
def _reversed(self):
1043
r"""
1044
Reverses the permutation.
1045
1046
EXAMPLES:
1047
1048
::
1049
1050
sage: p = iet.GeneralizedPermutation('a b b','c c a',reduced=True)
1051
sage: p._reversed()
1052
sage: p
1053
a a b
1054
b c c
1055
1056
::
1057
1058
sage: p = iet.GeneralizedPermutation('a a','b b c c',reduced=True)
1059
sage: p._reversed()
1060
sage: p
1061
a a
1062
b b c c
1063
"""
1064
tmp = [self._twin[0][:], self._twin[1][:]]
1065
1066
n = self.length()
1067
1068
for i in (0,1):
1069
for j in range(n[i]):
1070
interval, position = self._twin[i][j]
1071
tmp[i][n[i] - 1 - j] = (
1072
interval,
1073
n[interval] - 1 - position)
1074
1075
self._twin = tmp
1076
1077
def _inversed(self):
1078
r"""
1079
Inverses the permutation.
1080
1081
EXAMPLES:
1082
1083
::
1084
1085
sage: p = iet.GeneralizedPermutation('a a','b b',reduced=True)
1086
sage: p._inversed()
1087
sage: p
1088
a a
1089
b b
1090
1091
::
1092
1093
sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True)
1094
sage: p._inversed()
1095
sage: p
1096
a b b
1097
c c a
1098
1099
::
1100
1101
sage: p = iet.GeneralizedPermutation('a a','b b c c',reduced=True)
1102
sage: p._inversed()
1103
sage: p
1104
a a b b
1105
c c
1106
"""
1107
self._twin = [self._twin[1], self._twin[0]]
1108
1109
for interval in (0,1):
1110
for j in xrange(self.length(interval)):
1111
self._twin[interval][j] = (1-self._twin[interval][j][0],
1112
self._twin[interval][j][1])
1113
1114
def rauzy_diagram(self, **kargs):
1115
r"""
1116
Returns the associated Rauzy diagram.
1117
1118
The Rauzy diagram of a permutation corresponds to all permutations
1119
that we could obtain from this one by Rauzy move. The set obtained
1120
is a labelled Graph. The label of vertices being 0 or 1 depending
1121
on the type.
1122
1123
OUTPUT:
1124
1125
Rauzy diagram -- the graph of permutations obtained by rauzy induction
1126
1127
EXAMPLES::
1128
1129
sage: p = iet.Permutation('a b c d', 'd a b c')
1130
sage: d = p.rauzy_diagram()
1131
"""
1132
return ReducedRauzyDiagram(self, **kargs)
1133
1134
def labelize_flip(couple):
1135
r"""
1136
Returns a string from a 2-uple couple of the form (name, flip).
1137
1138
TESTS::
1139
1140
sage: from sage.combinat.iet.reduced import labelize_flip
1141
sage: labelize_flip((4,1))
1142
' 4'
1143
sage: labelize_flip(('a',-1))
1144
'-a'
1145
"""
1146
if couple[1] == -1: return '-' + str(couple[0])
1147
return ' ' + str(couple[0])
1148
1149
class FlippedReducedPermutation(ReducedPermutation):
1150
r"""
1151
Flipped Reduced Permutation.
1152
1153
.. warning::
1154
1155
Internal class! Do not use directly!
1156
1157
INPUT:
1158
1159
- ``intervals`` - a list of two lists
1160
1161
- ``flips`` - the flipped letters
1162
1163
- ``alphabet`` - an alphabet
1164
"""
1165
def __init__(self, intervals=None, flips=None, alphabet=None):
1166
r"""
1167
TESTS::
1168
1169
sage: p = iet.Permutation('a b','b a',reduced=True,flips='a')
1170
sage: p == loads(dumps(p))
1171
True
1172
sage: p = iet.Permutation('a b','b a',reduced=True,flips='b')
1173
sage: p == loads(dumps(p))
1174
True
1175
sage: p = iet.Permutation('a b','b a',reduced=True,flips='ab')
1176
sage: p == loads(dumps(p))
1177
True
1178
sage: p = iet.GeneralizedPermutation('a a','b b',reduced=True,flips='a')
1179
sage: p == loads(dumps(p))
1180
True
1181
sage: p = iet.GeneralizedPermutation('a a','b b',reduced=True,flips='b')
1182
sage: p == loads(dumps(p))
1183
True
1184
sage: p = iet.GeneralizedPermutation('a a','b b',reduced=True,flips='ab')
1185
sage: p == loads(dumps(p))
1186
True
1187
"""
1188
self._hash = None
1189
1190
if intervals is None:
1191
self._twin = [[],[]]
1192
self._flips = [[],[]]
1193
self._alphabet = None
1194
1195
else:
1196
if flips is None: flips = []
1197
1198
if alphabet is None : self._init_alphabet(intervals)
1199
else : self._alphabet = Alphabet(alphabet)
1200
1201
self._init_twin(intervals)
1202
self._init_flips(intervals, flips)
1203
1204
self._hash = None
1205
1206
def __copy__(self):
1207
r"""
1208
Returns a copy of self.
1209
1210
TESTS::
1211
1212
sage: p = iet.GeneralizedPermutation('a a b', 'c c b',reduced=True, flips='a')
1213
sage: q = copy(p)
1214
sage: p == q
1215
True
1216
sage: p is q
1217
False
1218
"""
1219
p = self.__class__()
1220
1221
p._twin = [self._twin[0][:], self._twin[1][:]]
1222
p._flips = [self._flips[0][:], self._flips[1][:]]
1223
p._alphabet = self._alphabet
1224
p._repr_type = self._repr_type
1225
p._repr_options = self._repr_options
1226
1227
return p
1228
1229
def right_rauzy_move(self, winner):
1230
r"""
1231
Performs a Rauzy move on the right.
1232
1233
EXAMPLE::
1234
1235
sage: p = iet.Permutation('a b c','c b a',reduced=True,flips='c')
1236
sage: p.right_rauzy_move('top')
1237
-a b -c
1238
-a -c b
1239
"""
1240
winner = interval_conversion(winner)
1241
1242
result = copy(self)
1243
1244
loser_to = result._get_loser_to(winner)
1245
1246
result._flip_rauzy_move(winner, loser_to)
1247
result._twin_rauzy_move(winner, loser_to)
1248
1249
return result
1250
1251
def _reversed(self):
1252
r"""
1253
Reverses the permutation
1254
1255
TESTS:
1256
1257
::
1258
1259
sage: p = iet.Permutation('a b c d','c d b a',reduced=True,flips='a')
1260
sage: p
1261
-a b c d
1262
c d b -a
1263
sage: p._reversed()
1264
sage: p
1265
a b c -d
1266
-d c a b
1267
sage: p._reversed()
1268
sage: p
1269
-a b c d
1270
c d b -a
1271
1272
::
1273
1274
sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True,flips='a')
1275
sage: p
1276
-a -a b
1277
b c c
1278
sage: p._reversed()
1279
sage: p
1280
a -b -b
1281
c c a
1282
sage: p._reversed()
1283
sage: p
1284
-a -a b
1285
b c c
1286
"""
1287
super(FlippedReducedPermutation, self)._reversed()
1288
self._flips[0].reverse()
1289
self._flips[1].reverse()
1290
1291
def _inversed(self):
1292
r"""
1293
Inverses the permutation.
1294
1295
TESTS:
1296
1297
::
1298
1299
sage: p = iet.Permutation('a b c d','c d b a',flips='a')
1300
sage: p
1301
-a b c d
1302
c d b -a
1303
sage: p._inversed()
1304
sage: p
1305
c d b -a
1306
-a b c d
1307
sage: p._inversed()
1308
sage: p
1309
-a b c d
1310
c d b -a
1311
1312
::
1313
1314
sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True,flips='a')
1315
sage: p
1316
-a -a b
1317
b c c
1318
sage: p._inversed()
1319
sage: p
1320
a b b
1321
-c -c a
1322
sage: p._inversed()
1323
sage: p
1324
-a -a b
1325
b c c
1326
"""
1327
super(FlippedReducedPermutation, self)._inversed()
1328
self._flips.reverse()
1329
1330
class FlippedReducedPermutationIET(
1331
FlippedReducedPermutation,
1332
FlippedPermutationIET,
1333
ReducedPermutationIET):
1334
r"""
1335
Flipped Reduced Permutation from iet
1336
1337
EXAMPLES
1338
1339
::
1340
1341
sage: p = iet.Permutation('a b c', 'c b a', flips=['a'], reduced=True)
1342
sage: p.rauzy_move(1)
1343
-a -b c
1344
-a c -b
1345
1346
TESTS::
1347
1348
sage: p = iet.Permutation('a b','b a',flips=['a'])
1349
sage: p == loads(dumps(p))
1350
True
1351
"""
1352
def __cmp__(self, other):
1353
r"""
1354
Defines a natural lexicographic order.
1355
1356
TESTS::
1357
1358
sage: p = iet.Permutation('a b','a b',reduced=True,flips='a')
1359
sage: q = copy(p)
1360
sage: q.alphabet([0,1])
1361
sage: p == q
1362
True
1363
sage: l0 = ['a b','a b']
1364
sage: l1 = ['a b','b a']
1365
sage: l2 = ['b a', 'a b']
1366
sage: p0 = iet.Permutation(l0, reduced=True, flips='ab')
1367
sage: p1 = iet.Permutation(l1, reduced=True, flips='a')
1368
sage: p2 = iet.Permutation(l2, reduced=True, flips='b')
1369
sage: p3 = iet.Permutation(l1, reduced=True, flips='ab')
1370
sage: p4 = iet.Permutation(l2 ,reduced=True,flips='ab')
1371
sage: p0 == p1 or p0 == p2 or p0 == p3 or p0 == p4
1372
False
1373
sage: p0 != p1 and p0 != p2 and p0 != p3 and p0 != p4
1374
True
1375
sage: p1 == p2 and p3 == p4
1376
True
1377
sage: p1 != p2 or p3 != p4
1378
False
1379
sage: p1 == p3 or p1 == p4 or p2 == p3 or p2 == p4
1380
False
1381
sage: p1 != p3 and p1 != p4 and p2 != p3 and p2 != p4
1382
True
1383
sage: p1 = iet.Permutation(l1,reduced=True, flips='a')
1384
sage: p2 = iet.Permutation(l1,reduced=True, flips='b')
1385
sage: p3 = iet.Permutation(l1,reduced=True, flips='ab')
1386
sage: p2 > p3 and p3 < p2
1387
True
1388
sage: p1 > p2 and p2 < p1
1389
True
1390
sage: p1 > p3 and p3 < p1
1391
True
1392
sage: q1 = iet.Permutation(l0, reduced=True, flips='a')
1393
sage: q2 = iet.Permutation(l0, reduced=True, flips='b')
1394
sage: q3 = iet.Permutation(l0, reduced=True, flips='ab')
1395
sage: q2 > q1 and q2 > q3 and q1 < q2 and q3 < q2
1396
True
1397
sage: q1 > q3
1398
True
1399
sage: q3 < q1
1400
True
1401
sage: r = iet.Permutation('a b c','a b c', reduced=True, flips='a')
1402
sage: r > p1 and r > p2 and r > p3
1403
True
1404
sage: p1 < r and p2 < r and p3 < r
1405
True
1406
"""
1407
if type(self) != type(other):
1408
return -1
1409
1410
if len(self) > len(other):
1411
return 1
1412
elif len(self) < len(other):
1413
return -1
1414
1415
n = len(self)
1416
j = 0
1417
while (j < n and
1418
self._twin[1][j] == other._twin[1][j] and
1419
self._flips[1][j] == other._flips[1][j]):
1420
j += 1
1421
1422
if j != n:
1423
if self._twin[1][j] > other._twin[1][j]: return 1
1424
elif self._twin[1][j] < other._twin[1][j]: return -1
1425
else: return self._flips[1][j]
1426
1427
return 0
1428
1429
def list(self, flips=False):
1430
r"""
1431
Returns a list representation of self.
1432
1433
INPUT:
1434
1435
- ``flips`` - boolean (default: False) if True the output contains
1436
2-uple of (label, flip)
1437
1438
EXAMPLES:
1439
1440
::
1441
sage: p = iet.Permutation('a b','b a',reduced=True,flips='b')
1442
sage: p.list(flips=True)
1443
[[('a', 1), ('b', -1)], [('b', -1), ('a', 1)]]
1444
sage: p.list(flips=False)
1445
[['a', 'b'], ['b', 'a']]
1446
sage: p.alphabet([0,1])
1447
sage: p.list(flips=True)
1448
[[(0, 1), (1, -1)], [(1, -1), (0, 1)]]
1449
sage: p.list(flips=False)
1450
[[0, 1], [1, 0]]
1451
1452
One can recover the initial permutation from this list::
1453
1454
sage: p = iet.Permutation('a b','b a',reduced=True,flips='a')
1455
sage: iet.Permutation(p.list(), flips=p.flips(), reduced=True) == p
1456
True
1457
"""
1458
if flips:
1459
a0 = zip(map(self.alphabet().unrank, range(0,len(self))), self._flips[0])
1460
a1 = zip(map(self.alphabet().unrank, self._twin[1]), self._flips[1])
1461
1462
else:
1463
a0 = map(self.alphabet().unrank, range(0,len(self)))
1464
a1 = map(self.alphabet().unrank, self._twin[1])
1465
1466
return [a0,a1]
1467
1468
def _get_loser_to(self, winner) :
1469
r"""
1470
This function return the position of the future loser position.
1471
1472
TESTS:
1473
1474
::
1475
1476
sage: p = iet.GeneralizedPermutation('a b b','c c a', reduced=True, flips='ab')
1477
sage: p._get_loser_to(0)
1478
(0, 2)
1479
sage: p._get_loser_to(1)
1480
(0, 0)
1481
1482
::
1483
1484
sage: p = iet.GeneralizedPermutation('a a','b b c c',reduced=True,flips='a')
1485
sage: p._get_loser_to(0)
1486
(0, 1)
1487
"""
1488
if self._flips[winner][-1] == 1 :
1489
return (1-winner, self._twin[winner][-1]+1)
1490
else :
1491
return (1-winner, self._twin[winner][-1])
1492
1493
def _flip_rauzy_move(self, winner, loser_to):
1494
r"""
1495
Performs a Rauzy move on flips.
1496
1497
TESTS::
1498
1499
sage: p = iet.GeneralizedPermutation('a b b','c c a', reduced=True, flips='ab')
1500
sage: p
1501
-a -b -b
1502
c c -a
1503
sage: p.rauzy_move(1) #indirect doctest
1504
a -b a
1505
c c -b
1506
sage: p.rauzy_move(0) #indirect doctest
1507
a -b a -b
1508
c c
1509
"""
1510
loser = 1 - winner
1511
1512
loser_twin_interval, loser_twin_position = winner, self._twin[loser][-1]
1513
loser_interval_to, loser_position_to = loser_to
1514
1515
flip = self._flips[winner][-1] * self._flips[loser][-1]
1516
1517
self._flips[loser_twin_interval][loser_twin_position] = flip
1518
1519
del self._flips[loser][-1]
1520
self._flips[loser_interval_to].insert(loser_position_to, flip)
1521
1522
def rauzy_diagram(self, **kargs):
1523
r"""
1524
Returns the associated Rauzy diagram.
1525
1526
EXAMPLES::
1527
1528
sage: p = iet.Permutation('a b','b a',reduced=True,flips='a')
1529
sage: r = p.rauzy_diagram()
1530
sage: p in r
1531
True
1532
"""
1533
return FlippedReducedRauzyDiagram(self, **kargs)
1534
1535
class FlippedReducedPermutationLI(
1536
FlippedReducedPermutation,
1537
FlippedPermutationLI,
1538
ReducedPermutationLI):
1539
r"""
1540
Flipped Reduced Permutation from li
1541
1542
EXAMPLES:
1543
1544
Creation using the GeneralizedPermutation function::
1545
1546
sage: p = iet.GeneralizedPermutation('a a b', 'b c c', reduced=True, flips='a')
1547
"""
1548
def _get_loser_to(self, winner) :
1549
r"""
1550
This function return the position of the future loser position.
1551
1552
TESTS:
1553
1554
::
1555
1556
sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True,flips='b')
1557
sage: p._get_loser_to(0)
1558
(1, 0)
1559
sage: p._get_loser_to(1)
1560
(1, 1)
1561
1562
::
1563
1564
sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True,flips='c')
1565
sage: p._get_loser_to(0)
1566
(1, 1)
1567
sage: p._get_loser_to(1)
1568
(1, 2)
1569
"""
1570
loser = 1 - winner
1571
1572
if self._twin[winner][-1][0] == loser :
1573
if self._flips[winner][-1] == 1 :
1574
return (loser, self._twin[winner][-1][1] + 1)
1575
else :
1576
return (loser, self._twin[winner][-1][1])
1577
else :
1578
if self._flips[winner][-1] == 1 :
1579
return (winner, self._twin[winner][-1][1])
1580
else :
1581
return (winner, self._twin[winner][-1][1] + 1)
1582
1583
def _flip_rauzy_move(self, winner, loser_to):
1584
r"""
1585
Performs a Rauzy move on flips
1586
1587
TESTS::
1588
1589
sage: p = iet.GeneralizedPermutation('a a b','b c c',flips='b',reduced=True)
1590
sage: p
1591
a a -b
1592
-b c c
1593
sage: p.rauzy_move('top') #indirect doctest
1594
a a -b
1595
-c -b -c
1596
"""
1597
loser = 1 - winner
1598
1599
loser_twin_interval, loser_twin_position = self._twin[loser][-1]
1600
loser_interval_to, loser_position_to = loser_to
1601
1602
flip = self._flips[winner][-1] * self._flips[loser][-1]
1603
1604
self._flips[loser_twin_interval][loser_twin_position] = flip
1605
1606
del self._flips[loser][-1]
1607
self._flips[loser_interval_to].insert(loser_position_to, flip)
1608
1609
def list(self, flips=False):
1610
r"""
1611
Returns a list representation of self.
1612
1613
INPUT:
1614
1615
- ``flips`` - boolean (default: False) return the list with flips
1616
1617
EXAMPLES:
1618
1619
::
1620
1621
sage: p = iet.GeneralizedPermutation('a a','b b',reduced=True,flips='a')
1622
sage: p.list(flips=True)
1623
[[('a', -1), ('a', -1)], [('b', 1), ('b', 1)]]
1624
sage: p.list(flips=False)
1625
[['a', 'a'], ['b', 'b']]
1626
1627
sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True,flips='abc')
1628
sage: p.list(flips=True)
1629
[[('a', -1), ('a', -1), ('b', -1)], [('b', -1), ('c', -1), ('c', -1)]]
1630
sage: p.list(flips=False)
1631
[['a', 'a', 'b'], ['b', 'c', 'c']]
1632
1633
one can rebuild the permutation from the list::
1634
1635
sage: p = iet.GeneralizedPermutation('a a b','b c c',flips='a',reduced=True)
1636
sage: iet.GeneralizedPermutation(p.list(),flips=p.flips(),reduced=True) == p
1637
True
1638
"""
1639
i_a = 0
1640
l = [[False]*len(self._twin[0]),[False]*len(self._twin[1])]
1641
1642
if flips:
1643
for i in range(2): # False means empty here
1644
for j in range(len(l[i])):
1645
if l[i][j] is False:
1646
l[i][j] = (self._alphabet.unrank(i_a), self._flips[i][j])
1647
l[self._twin[i][j][0]][self._twin[i][j][1]] = l[i][j]
1648
i_a += 1
1649
1650
else:
1651
for i in range(2): # False means empty here
1652
for j in range(len(l[i])):
1653
if l[i][j] is False:
1654
l[i][j] = self._alphabet.unrank(i_a)
1655
l[self._twin[i][j][0]][self._twin[i][j][1]] = l[i][j]
1656
i_a += 1
1657
return l
1658
1659
def __eq__(self, other) :
1660
r"""
1661
TESTS::
1662
1663
sage: a0 = [0,0,1]
1664
sage: a1 = [1,2,2]
1665
sage: p = iet.GeneralizedPermutation(a0,a1,reduced=True,flips=[0])
1666
sage: q = copy(p)
1667
sage: q.alphabet("abc")
1668
sage: p == q
1669
True
1670
sage: b0 = [1,0,0]
1671
sage: b1 = [2,2,1]
1672
sage: r = iet.GeneralizedPermutation(b0,b1,reduced=True,flips=[0])
1673
sage: p == r or q == r
1674
False
1675
"""
1676
return (type(self) == type(other) and
1677
self._twin == other._twin and
1678
self._flips == other._flips)
1679
1680
def __ne__(self, other) :
1681
r"""
1682
TESTS::
1683
1684
sage: a0 = [0,0,1]
1685
sage: a1 = [1,2,2]
1686
sage: p = iet.GeneralizedPermutation(a0,a1,reduced=True,flips=[0])
1687
sage: q = copy(p)
1688
sage: q.alphabet("abc")
1689
sage: p != q
1690
False
1691
sage: b0 = [1,0,0]
1692
sage: b1 = [2,2,1]
1693
sage: r = iet.GeneralizedPermutation(b0,b1,reduced=True,flips=[0])
1694
sage: p != r and q != r
1695
True
1696
"""
1697
return (type(self) != type(other) or
1698
self._twin != other._twin or
1699
self._flips != other._flips)
1700
1701
def rauzy_diagram(self, **kargs):
1702
r"""
1703
Returns the associated Rauzy diagram.
1704
1705
For more explanation and a list of arguments try help(iet.RauzyDiagram)
1706
1707
EXAMPLES::
1708
1709
sage: p = iet.GeneralizedPermutation('a a b','c c b',reduced=True)
1710
sage: r = p.rauzy_diagram()
1711
sage: p in r
1712
True
1713
"""
1714
return FlippedReducedRauzyDiagram(self, **kargs)
1715
1716
class ReducedRauzyDiagram(RauzyDiagram):
1717
r"""
1718
Rauzy diagram of reduced permutations
1719
"""
1720
def _permutation_to_vertex(self, p):
1721
r"""
1722
The necessary data to store the permutation.
1723
1724
TESTS::
1725
1726
1727
sage: p = iet.Permutation('a b c','c b a',reduced=True) #indirect doctest
1728
sage: r = p.rauzy_diagram()
1729
sage: p in r
1730
True
1731
"""
1732
return (tuple(p._twin[0]), tuple(p._twin[1]))
1733
1734
def _set_element(self, data=None):
1735
r"""
1736
Sets self._element with data.
1737
1738
TESTS::
1739
1740
sage: p = iet.Permutation('a b c','c b a',reduced=True)
1741
sage: r = p.rauzy_diagram()
1742
sage: p in r #indirect doctest
1743
True
1744
"""
1745
self._element._twin = [list(data[0]), list(data[1])]
1746
1747
class FlippedReducedRauzyDiagram(FlippedRauzyDiagram, ReducedRauzyDiagram):
1748
r"""
1749
Rauzy diagram of flipped reduced permutations.
1750
"""
1751
def _permutation_to_vertex(self, p):
1752
r"""
1753
TESTS::
1754
1755
sage: p = iet.GeneralizedPermutation('a b b','c c a',flips='a',reduced=True)
1756
sage: r = p.rauzy_diagram()
1757
sage: p in r #indirect doctest
1758
True
1759
"""
1760
return ((tuple(p._twin[0]), tuple(p._twin[1])),
1761
(tuple(p._flips[0]), tuple(p._flips[1])))
1762
1763
def _set_element(self, data=None):
1764
r"""
1765
Sets self._element with data.
1766
TESTS::
1767
1768
sage: r = iet.RauzyDiagram('a b c','c b a',flips='b',reduced=True) #indirect doctest
1769
"""
1770
self._element._twin = [list(data[0][0]), list(data[0][1])]
1771
self._element._flips = [list(data[1][0]), list(data[1][1])]
1772
1773
1774
1775