Path: blob/master/src/sage/dynamics/interval_exchanges/reduced.py
8815 views
r"""1Reduced permutations23A reduced (generalized) permutation is better suited to study strata of Abelian4(or quadratic) holomorphic forms on Riemann surfaces. The Rauzy diagram is an5invariant of such a component. Corentin Boissy proved the identification of6Rauzy diagrams with connected components of stratas. But the geometry of the7diagram and the relation with the strata is not yet totally understood.89AUTHORS:1011- Vincent Delecroix (2000-09-29): initial version1213TESTS::1415sage: from sage.dynamics.interval_exchanges.reduced import ReducedPermutationIET16sage: ReducedPermutationIET([['a','b'],['b','a']])17a b18b a19sage: ReducedPermutationIET([[1,2,3],[3,1,2]])201 2 3213 1 222sage: from sage.dynamics.interval_exchanges.reduced import ReducedPermutationLI23sage: ReducedPermutationLI([[1,1],[2,2,3,3,4,4]])241 1252 2 3 3 4 426sage: ReducedPermutationLI([['a','a','b','b','c','c'],['d','d']])27a a b b c c28d d29sage: from sage.dynamics.interval_exchanges.reduced import FlippedReducedPermutationIET30sage: FlippedReducedPermutationIET([[1,2,3],[3,2,1]],flips=[1,2])31-1 -2 3323 -2 -133sage: FlippedReducedPermutationIET([['a','b','c'],['b','c','a']],flips='b')34a -b c35-b c a36sage: from sage.dynamics.interval_exchanges.reduced import FlippedReducedPermutationLI37sage: FlippedReducedPermutationLI([[1,1],[2,2,3,3,4,4]], flips=[1,4])38-1 -1392 2 3 3 -4 -440sage: FlippedReducedPermutationLI([['a','a','b','b'],['c','c']],flips='ac')41-a -a b b42-c -c43sage: from sage.dynamics.interval_exchanges.reduced import ReducedRauzyDiagram44sage: p = ReducedPermutationIET([[1,2,3],[3,2,1]])45sage: d = ReducedRauzyDiagram(p)46"""47#*****************************************************************************48# Copyright (C) 2008 Vincent Delecroix <[email protected]>49#50# Distributed under the terms of the GNU General Public License (GPL)51# http://www.gnu.org/licenses/52#*****************************************************************************5354from sage.structure.sage_object import SageObject5556from copy import copy5758from sage.combinat.words.alphabet import Alphabet59from sage.rings.integer import Integer6061from template import PermutationIET, PermutationLI # permutations62from template import FlippedPermutationIET, FlippedPermutationLI # flipped permutations63from template import twin_list_iet, twin_list_li64from template import RauzyDiagram, FlippedRauzyDiagram6566from template import interval_conversion, side_conversion6768class ReducedPermutation(SageObject) :69r"""70Template for reduced objects.7172.. warning::7374Internal class! Do not use directly!7576INPUT:7778- ``intervals`` - a list of two list of labels7980- ``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.81"""82def __init__(self,intervals=None,alphabet=None):83r"""84TESTS::8586sage: from sage.dynamics.interval_exchanges.reduced import ReducedPermutationIET87sage: p = ReducedPermutationIET()88sage: loads(dumps(p)) == p89True90sage: p = ReducedPermutationIET([['a','b'],['b','a']])91sage: loads(dumps(p)) == p92True93sage: from sage.dynamics.interval_exchanges.reduced import ReducedPermutationLI94sage: p = ReducedPermutationLI()95sage: loads(dumps(p)) == p96True97sage: p = ReducedPermutationLI([['a','a'],['b','b']])98sage: loads(dumps(p)) == p99True100"""101self._hash = None102103if intervals is None:104self._twin = [[],[]]105self._alphabet = alphabet106107else:108self._init_twin(intervals)109110if alphabet is None:111self._init_alphabet(intervals)112else:113alphabet = Alphabet(alphabet)114if alphabet.cardinality() < len(self):115raise TypeError("The alphabet is too short")116self._alphabet = alphabet117118def __len__(self):119r"""120TESTS::121122sage: p = iet.Permutation('a b','b a',reduced=True)123sage: len(p)1242125sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True)126sage: len(p)1273128sage: p = iet.GeneralizedPermutation('a a','b b c c',reduced=True)129sage: len(p)1303131"""132return (len(self._twin[0]) + len(self._twin[1])) / 2133134def length_top(self):135r"""136Returns the number of intervals in the top segment.137138OUTPUT:139140integer -- the length of the top segment141142EXAMPLES::143144sage: p = iet.Permutation('a b c','c b a')145sage: p.length_top()1463147sage: p = iet.GeneralizedPermutation('a a b','c d c b d')148sage: p.length_top()1493150sage: p = iet.GeneralizedPermutation('a b c b d c d', 'e a e')151sage: p.length_top()1527153"""154return len(self._twin[0])155156def length_bottom(self):157r"""158Returns the number of intervals in the bottom segment.159160OUTPUT:161162integer -- the length of the bottom segment163164EXAMPLES::165166sage: p = iet.Permutation('a b c','c b a')167sage: p.length_bottom()1683169sage: p = iet.GeneralizedPermutation('a a b','c d c b d')170sage: p.length_bottom()1715172"""173return len(self._twin[1])174175def length(self, interval=None):176r"""177Returns the 2-uple of lengths.178179p.length() is identical to (p.length_top(), p.length_bottom())180If an interval is specified, it returns the length of the specified181interval.182183INPUT:184185- ``interval`` - None, 'top' (or 't' or 0) or 'bottom' (or 'b' or 1)186187OUTPUT:188189integer or 2-uple of integers -- the corresponding lengths190191EXAMPLES::192193sage: p = iet.Permutation('a b c','c b a')194sage: p.length()195(3, 3)196sage: p = iet.GeneralizedPermutation('a a b','c d c b d')197sage: p.length()198(3, 5)199"""200if interval is None :201return len(self._twin[0]),len(self._twin[1])202else :203interval = interval_conversion(interval)204return len(self._twin[interval])205206def __getitem__(self,i):207r"""208TESTS::209210sage: p = iet.Permutation('a b', 'b a', reduced=True)211sage: print p[0]212['a', 'b']213sage: print p[1]214['b', 'a']215sage: p.alphabet([0,1])216sage: print p[0]217[0, 1]218sage: print p[1]219[1, 0]220"""221return self.list().__getitem__(i)222223def __copy__(self) :224r"""225Returns a copy of self.226227EXAMPLES::228229sage: p = iet.Permutation('a b c', 'c b a', reduced=True)230sage: q = copy(p)231sage: p == q232True233sage: p is q234False235sage: p = iet.GeneralizedPermutation('a b b','c c a', reduced=True)236sage: q = copy(p)237sage: p == q238True239sage: p is q240False241"""242q = self.__class__()243244q._twin = [self._twin[0][:], self._twin[1][:]]245q._alphabet = self._alphabet246q._repr_type = self._repr_type247q._repr_options = self._repr_options248249return q250251def erase_letter(self, letter):252r"""253Erases a letter.254255INPUT:256257- ``letter`` - a letter which is a label of an interval of self258259EXAMPLES:260261::262263sage: p = iet.Permutation('a b c','c b a')264sage: p.erase_letter('a')265b c266c b267268::269270sage: p = iet.GeneralizedPermutation('a b b','c c a')271sage: p.erase_letter('a')272b b273c c274"""275l = self.list()276277del l[0][l[0].index(letter)]278del l[1][l[1].index(letter)]279280return self.__class__(l)281282def right_rauzy_move(self, winner):283r"""284Performs a Rauzy move on the right.285286EXAMPLES:287288::289290sage: p = iet.Permutation('a b c','c b a',reduced=True)291sage: p.right_rauzy_move(0)292a b c293c a b294sage: p.right_rauzy_move(1)295a b c296b c a297298::299300sage: p = iet.GeneralizedPermutation('a a','b b c c',reduced=True)301sage: p.right_rauzy_move(0)302a b b303c c a304"""305winner = interval_conversion(winner)306307result = copy(self)308309loser_to = result._get_loser_to(winner)310# beware here, loser_to can contain 2 or 3 items311# (depending on the presence of flip)312313result._twin_rauzy_move(winner, loser_to)314315return result316317def left_rauzy_move(self, winner):318r"""319Performs a Rauzy move on the left.320321EXAMPLES:322323::324325sage: p = iet.Permutation('a b c','c b a',reduced=True)326sage: p.left_rauzy_move(0)327a b c328b c a329sage: p.right_rauzy_move(1)330a b c331b c a332333::334335sage: p = iet.GeneralizedPermutation('a a','b b c c',reduced=True)336sage: p.left_rauzy_move(0)337a a b338b c c339"""340winner = interval_conversion(winner)341342result = copy(self)343result._reversed()344result = result.right_rauzy_move(winner)345result._reversed()346return result347348_RP = ReducedPermutation349350def alphabetized_atwin(twin, alphabet):351"""352Alphabetization of a twin of iet.353354TESTS::355356sage: from sage.dynamics.interval_exchanges.reduced import alphabetized_atwin357358::359360sage: twin = [[0,1],[0,1]]361sage: alphabet = Alphabet("ab")362sage: alphabetized_atwin(twin, alphabet)363[['a', 'b'], ['a', 'b']]364365::366367sage: twin = [[1,0],[1,0]]368sage: alphabet = Alphabet([0,1])369sage: alphabetized_atwin(twin, alphabet)370[[0, 1], [1, 0]]371372::373374sage: twin = [[1,2,3,0],[3,0,1,2]]375sage: alphabet = Alphabet("abcd")376sage: alphabetized_atwin(twin,alphabet)377[['a', 'b', 'c', 'd'], ['d', 'a', 'b', 'c']]378"""379l = [[],[]]380381l[0] = map(lambda x: alphabet.unrank(x), range(len(twin[0])))382l[1] = map(lambda x: alphabet.unrank(x), twin[1])383384return l385386def ReducedPermutationsIET_iterator(387nintervals=None,388irreducible=True,389alphabet=None):390r"""391Returns an iterator over reduced permutations392393INPUT:394395- ``nintervals`` - integer or None396397- ``irreducible`` - boolean398399- ``alphabet`` - something that should be converted to an alphabet400of at least nintervals letters401402TESTS::403404sage: for p in iet.Permutations_iterator(3,reduced=True,alphabet="abc"):405....: print p #indirect doctest406a b c407b c a408a b c409c a b410a b c411c b a412"""413from itertools import imap,ifilter414from sage.combinat.permutation import Permutations415416if irreducible is False:417if nintervals is None:418raise ValueError("please choose a number of intervals")419420nintervals = Integer(nintervals)421422if not(nintervals > 0):423raise ValueError('number of intervals must be positive')424425a0 = range(1,nintervals+1)426f = lambda x: ReducedPermutationIET([a0,list(x)],427alphabet=alphabet)428return imap(f, Permutations(nintervals))429else:430return ifilter(lambda x: x.is_irreducible(),431ReducedPermutationsIET_iterator(nintervals,False,alphabet))432433class ReducedPermutationIET(ReducedPermutation, PermutationIET):434"""435Reduced permutation from iet436437Permutation from iet without numerotation of intervals. For initialization,438you should use GeneralizedPermutation which is the class factory for all439permutation types.440441EXAMPLES:442443Equality testing (no equality of letters but just of ordering)::444445sage: p = iet.Permutation('a b c', 'c b a', reduced = True)446sage: q = iet.Permutation('p q r', 'r q p', reduced = True)447sage: p == q448True449450Reducibility testing::451452sage: p = iet.Permutation('a b c', 'c b a', reduced = True)453sage: p.is_irreducible()454True455456::457458sage: q = iet.Permutation('a b c d', 'b a d c', reduced = True)459sage: q.is_irreducible()460False461462463Rauzy movability and Rauzy move::464465sage: p = iet.Permutation('a b c', 'c b a', reduced = True)466sage: p.has_rauzy_move(1)467True468sage: print p.rauzy_move(1)469a b c470b c a471472Rauzy diagrams::473474sage: p = iet.Permutation('a b c d', 'd a b c')475sage: p_red = iet.Permutation('a b c d', 'd a b c', reduced = True)476sage: d = p.rauzy_diagram()477sage: d_red = p_red.rauzy_diagram()478sage: p.rauzy_move(0) in d479True480sage: print d.cardinality(), d_red.cardinality()48112 6482"""483def _init_twin(self, a):484r"""485Initializes the _twin attribute486487TESTS::488489sage: p = iet.Permutation('a b','b a',reduced=True) #indirect doctest490sage: p._twin491[[1, 0], [1, 0]]492"""493self._twin = twin_list_iet(a)494495def list(self):496r"""497Returns a list of two list that represents the permutation.498499EXAMPLES::500501sage: p = iet.GeneralizedPermutation('a b','b a',reduced=True)502sage: p.list() == [p[0], p[1]]503True504sage: p.list() == [['a', 'b'], ['b', 'a']]505True506507::508509sage: p = iet.GeneralizedPermutation('a b c', 'b c a',reduced=True)510sage: iet.GeneralizedPermutation(p.list(),reduced=True) == p511True512"""513a0 = map(self._alphabet.unrank, range(0,len(self)))514a1 = map(self._alphabet.unrank, self._twin[1])515return [a0,a1]516517def is_identity(self):518r"""519Returns True if self is the identity.520521EXAMPLES::522523sage: iet.Permutation("a b","a b",reduced=True).is_identity()524True525sage: iet.Permutation("a b","b a",reduced=True).is_identity()526False527"""528for i in range(len(self)):529if self._twin[0][i] != i:530return False531return True532533def __hash__(self):534r"""535Returns a hash value (does not depends of the alphabet).536537TESTS::538sage: p = iet.Permutation([1,2],[1,2], reduced=True)539sage: q = iet.Permutation([1,2],[2,1], reduced=True)540sage: r = iet.Permutation([2,1],[1,2], reduced=True)541sage: hash(p) == hash(q)542False543sage: hash(q) == hash(r)544True545"""546if self._hash is None:547self._hash = hash(tuple(self._twin[0]))548return self._hash549550def __cmp__(self, other):551r"""552Defines a natural lexicographic order.553554TESTS::555556sage: p = iet.GeneralizedPermutation('a b','a b',reduced=True)557sage: q = copy(p)558sage: q.alphabet([0,1])559sage: p == q560True561sage: p0 = iet.GeneralizedPermutation('a b', 'a b', reduced=True)562sage: p1 = iet.GeneralizedPermutation('a b', 'b a', reduced=True)563sage: p0 < p1 and p1 > p0564True565sage: q0 = iet.GeneralizedPermutation('a b c','a b c',reduced=True)566sage: q1 = iet.GeneralizedPermutation('a b c','a c b',reduced=True)567sage: q2 = iet.GeneralizedPermutation('a b c','b a c',reduced=True)568sage: q3 = iet.GeneralizedPermutation('a b c','b c a',reduced=True)569sage: q4 = iet.GeneralizedPermutation('a b c','c a b',reduced=True)570sage: q5 = iet.GeneralizedPermutation('a b c','c b a',reduced=True)571sage: p0 < q0 and q0 > p0 and p1 < q0 and q0 > p1572True573sage: q0 < q1 and q1 > q0574True575sage: q1 < q2 and q2 > q1576True577sage: q2 < q3 and q3 > q2578True579sage: q3 < q4 and q4 > q3580True581sage: q4 < q5 and q5 > q4582True583"""584if type(self) != type(other):585raise ValueError("Permutations must be of the same type")586587if len(self) > len(other):588return 1589elif len(self) < len(other):590return -1591592n = len(self)593j = 0594while (j < n and self._twin[1][j] == other._twin[1][j]):595j += 1596597if j != n:598if self._twin[1][j] > other._twin[1][j]: return 1599else: return -1600601return 0602603def _reversed(self):604r"""605Reverses the permutation.606607EXAMPLES:608609::610611sage: p = iet.Permutation('a b c','c a b',reduced=True)612sage: p613a b c614c a b615sage: p._reversed()616sage: p617a b c618b c a619620::621622sage: p = iet.Permutation('a b c d','d a b c',reduced=True)623sage: p624a b c d625d a b c626sage: p._reversed()627sage: p628a b c d629b c d a630"""631tmp = [self._twin[0][:], self._twin[1][:]]632633n = self.length_top()634for i in (0, 1):635for j in range(n):636tmp[i][n - 1 - j] = n - 1 - self._twin[i][j]637638self._twin = tmp639640def _inversed(self):641r"""642Inverses the permutation.643644EXAMPLES:645646::647648sage: p = iet.Permutation('a b c','c a b',reduced=True)649sage: p650a b c651c a b652sage: p._inversed()653sage: p654a b c655b c a656657::658659sage: p = iet.Permutation('a b c d','d a b c',reduced=True)660sage: p661a b c d662d a b c663sage: p._inversed()664sage: p665a b c d666b c d a667"""668self._twin = [self._twin[1], self._twin[0]]669670def has_rauzy_move(self, winner, side='right'):671r"""672Tests if the permutation is rauzy_movable on the left.673674EXAMPLES:675676::677678sage: p = iet.Permutation('a b c','a c b',reduced=True)679sage: p.has_rauzy_move(0,'right')680True681sage: p.has_rauzy_move(0,'left')682False683sage: p.has_rauzy_move(1,'right')684True685sage: p.has_rauzy_move(1,'left')686False687688::689690sage: p = iet.Permutation('a b c d','c a b d',reduced=True)691sage: p.has_rauzy_move(0,'right')692False693sage: p.has_rauzy_move(0,'left')694True695sage: p.has_rauzy_move(1,'right')696False697sage: p.has_rauzy_move(1,'left')698True699"""700side = side_conversion(side)701winner = interval_conversion(winner)702703return self._twin[winner][side] % len(self) != side % len(self)704705def rauzy_move_relabel(self, winner, side='right'):706r"""707Returns the relabelization obtained from this move.708709EXAMPLE::710711sage: p = iet.Permutation('a b c d','d c b a')712sage: q = p.reduced()713sage: p_t = p.rauzy_move('t')714sage: q_t = q.rauzy_move('t')715sage: s_t = q.rauzy_move_relabel('t')716sage: s_t717WordMorphism: a->a, b->b, c->c, d->d718sage: map(s_t, p_t[0]) == map(Word, q_t[0])719True720sage: map(s_t, p_t[1]) == map(Word, q_t[1])721True722sage: p_b = p.rauzy_move('b')723sage: q_b = q.rauzy_move('b')724sage: s_b = q.rauzy_move_relabel('b')725sage: s_b726WordMorphism: a->a, b->d, c->b, d->c727sage: map(s_b, q_b[0]) == map(Word, p_b[0])728True729sage: map(s_b, q_b[1]) == map(Word, p_b[1])730True731"""732from sage.dynamics.interval_exchanges.labelled import LabelledPermutationIET733from sage.combinat.words.morphism import WordMorphism734735winner = interval_conversion(winner)736side = side_conversion(side)737738p = LabelledPermutationIET(self.list())739740l0_q = p.rauzy_move(winner, side).list()[0]741742d = dict([(self._alphabet[i],l0_q[i]) for i in range(len(self))])743744return WordMorphism(d)745746def _get_loser_to(self, winner) :747r"""748This function return the position of the future loser position.749750TESTS:751752::753754sage: p = iet.Permutation('a b c','c b a',reduced=True)755sage: p._get_loser_to(0)756(1, 1)757sage: p._get_loser_to(1)758(0, 1)759760::761762sage: p = iet.Permutation('a b c','c a b',reduced=True)763sage: p._get_loser_to(0)764(1, 1)765sage: p._get_loser_to(1)766(0, 2)767768::769770sage: p = iet.Permutation('a b c','b c a',reduced=True)771sage: p._get_loser_to(0)772(1, 2)773sage: p._get_loser_to(1)774(0, 1)775"""776return (1-winner, self._twin[winner][-1]+1)777778def _twin_rauzy_move(self, winner_interval, loser_to) :779r"""780Do a Rauzy move for this choice of winner.781782TESTS::783784sage: p = iet.Permutation('a b','b a',reduced=True)785sage: p.rauzy_move(0) == p #indirect doctest786True787sage: p.rauzy_move(1) == p #indirect doctest788True789"""790loser_interval = 1 - winner_interval791792loser_twin_interval = winner_interval793loser_twin_position = self._twin[loser_interval][-1]794795loser_interval_to, loser_position_to = loser_to796797# move the loser798del self._twin[loser_interval][-1]799self._twin[loser_interval_to].insert(loser_position_to, loser_twin_position)800self._twin[loser_twin_interval][loser_twin_position] = loser_position_to801802# increment the twins in the winner interval803for j in range(loser_position_to + 1, self.length(loser_interval_to)) :804self._twin[winner_interval][self._twin[loser_interval_to][j]] += 1805806def rauzy_diagram(self, **kargs):807r"""808Returns the associated Rauzy diagram.809810OUTPUT:811812A Rauzy diagram813814EXAMPLES:815816::817818sage: p = iet.Permutation('a b c d', 'd a b c',reduced=True)819sage: d = p.rauzy_diagram()820sage: p.rauzy_move(0) in d821True822sage: p.rauzy_move(1) in d823True824825For more information, try help RauzyDiagram826"""827return ReducedRauzyDiagram(self, **kargs)828829def alphabetized_qtwin(twin, alphabet):830"""831Alphabetization of a qtwin.832833TESTS::834835sage: from sage.dynamics.interval_exchanges.reduced import alphabetized_qtwin836837::838839sage: twin = [[(1,0),(1,1)],[(0,0),(0,1)]]840sage: alphabet = Alphabet("ab")841sage: print alphabetized_qtwin(twin,alphabet)842[['a', 'b'], ['a', 'b']]843844::845846sage: twin = [[(1,1), (1,0)],[(0,1), (0,0)]]847sage: alphabet=Alphabet("AB")848sage: alphabetized_qtwin(twin,alphabet)849[['A', 'B'], ['B', 'A']]850sage: alphabet=Alphabet("BA")851sage: alphabetized_qtwin(twin,alphabet)852[['B', 'A'], ['A', 'B']]853854::855856sage: twin = [[(0,1),(0,0)],[(1,1),(1,0)]]857sage: alphabet=Alphabet("ab")858sage: print alphabetized_qtwin(twin,alphabet)859[['a', 'a'], ['b', 'b']]860861::862863sage: twin = [[(0,2),(1,1),(0,0)],[(1,2),(0,1),(1,0)]]864sage: alphabet=Alphabet("abc")865sage: print alphabetized_qtwin(twin,alphabet)866[['a', 'b', 'a'], ['c', 'b', 'c']]867"""868i_a = 0869l = [[False]*len(twin[0]), [False]*len(twin[1])]870# False means empty here871for i in range(2) :872for j in range(len(l[i])) :873if l[i][j] is False :874l[i][j] = alphabet[i_a]875l[twin[i][j][0]][twin[i][j][1]] = alphabet[i_a]876i_a += 1877return l878879class ReducedPermutationLI(ReducedPermutation, PermutationLI):880r"""881Reduced quadratic (or generalized) permutation.882883EXAMPLES:884885Reducibility testing::886887sage: p = iet.GeneralizedPermutation('a b b', 'c c a', reduced = True)888sage: p.is_irreducible()889True890891::892893sage: p = iet.GeneralizedPermutation('a b c a', 'b d d c', reduced = True)894sage: p.is_irreducible()895False896sage: test, decomposition = p.is_irreducible(return_decomposition = True)897sage: test898False899sage: decomposition900(['a'], ['c', 'a'], [], ['c'])901902Rauzy movavability and Rauzy move::903904sage: p = iet.GeneralizedPermutation('a b b', 'c c a', reduced = True)905sage: p.has_rauzy_move(0)906True907sage: p.rauzy_move(0)908a a b b909c c910sage: p.rauzy_move(0).has_rauzy_move(0)911False912sage: p.rauzy_move(1)913a b b914c c a915916Rauzy diagrams::917918sage: p_red = iet.GeneralizedPermutation('a b b', 'c c a', reduced = True)919sage: d_red = p_red.rauzy_diagram()920sage: d_red.cardinality()9214922"""923def _init_twin(self, a):924r"""925Initializes the _twin attribute926927TESTS::928929sage: p = iet.GeneralizedPermutation('a a','b b',reduced=True) #indirect doctest930sage: p._twin931[[(0, 1), (0, 0)], [(1, 1), (1, 0)]]932"""933self._twin = twin_list_li(a)934935def list(self) :936r"""937The permutations as a list of two lists.938939EXAMPLES::940941sage: p = iet.GeneralizedPermutation('a b b', 'c c a', reduced = True)942sage: list(p)943[['a', 'b', 'b'], ['c', 'c', 'a']]944"""945return alphabetized_qtwin(self._twin, self.alphabet())946947def __eq__(self, other) :948r"""949Tests equality.950951Two reduced permutations are equal if they have the same order of952apparition of intervals. Non necessarily the same alphabet.953954TESTS::955956sage: p = iet.GeneralizedPermutation('a b b', 'c c a', reduced = True)957sage: q = iet.GeneralizedPermutation('b a a', 'c c b', reduced = True)958sage: r = iet.GeneralizedPermutation('t s s', 'w w t', reduced = True)959sage: p == q960True961sage: p == r962True963"""964return type(self) == type(other) and self._twin == other._twin965966def __ne__(self, other) :967"""968Tests difference.969970TESTS::971sage: p = iet.GeneralizedPermutation('a b b', 'c c a', reduced = True)972sage: q = iet.GeneralizedPermutation('b b a', 'c c a', reduced = True)973sage: r = iet.GeneralizedPermutation('i j j', 'k k i', reduced = True)974sage: p != q975True976sage: p != r977False978"""979return type(self) != type(other) or (self._twin != other._twin)980981def _get_loser_to(self, winner) :982r"""983This function return the position of the future loser position.984985TESTS::986987sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True)988sage: p._get_loser_to(0)989(1, 1)990sage: p._get_loser_to(1)991(1, 1)992"""993loser = 1 - winner994995if self._twin[winner][-1][0] == loser:996return (loser, self._twin[winner][-1][1] + 1)997else:998return (winner, self._twin[winner][-1][1])9991000def _twin_rauzy_move(self, winner_interval, loser_to) :1001r"""1002Rauzy move on the twin data10031004TESTS:10051006::10071008sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True)1009sage: p.rauzy_move(0) #indirect doctest1010a a b1011b c c1012sage: p.rauzy_move(1) #indirect doctest1013a a1014b b c c10151016::10171018sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True)1019sage: p.rauzy_move(0) #indirect doctest1020a a b1021b c c1022sage: p.rauzy_move(1) #indirect doctest1023a a1024b b c c1025"""1026loser_interval = 1 - winner_interval10271028loser_interval_to, loser_position_to = loser_to1029loser_twin_interval, loser_twin_position = self._twin[loser_interval][-1]10301031# increment the twins in the winner interval1032interval = [(self._twin[loser_interval_to][j], j) for j in range(loser_position_to, len(self._twin[loser_interval_to]))]1033for (i,j),k in interval : self._twin[i][j] = (loser_interval_to, k+1)10341035# prepare the loser new position in its twin1036self._twin[loser_twin_interval][loser_twin_position] = loser_to10371038# move the loser1039loser_twin = self._twin[loser_interval][-1]1040self._twin[loser_interval_to].insert(loser_position_to, loser_twin)1041del self._twin[loser_interval][-1]10421043def _reversed(self):1044r"""1045Reverses the permutation.10461047EXAMPLES:10481049::10501051sage: p = iet.GeneralizedPermutation('a b b','c c a',reduced=True)1052sage: p._reversed()1053sage: p1054a a b1055b c c10561057::10581059sage: p = iet.GeneralizedPermutation('a a','b b c c',reduced=True)1060sage: p._reversed()1061sage: p1062a a1063b b c c1064"""1065tmp = [self._twin[0][:], self._twin[1][:]]10661067n = self.length()10681069for i in (0,1):1070for j in range(n[i]):1071interval, position = self._twin[i][j]1072tmp[i][n[i] - 1 - j] = (1073interval,1074n[interval] - 1 - position)10751076self._twin = tmp10771078def _inversed(self):1079r"""1080Inverses the permutation.10811082EXAMPLES:10831084::10851086sage: p = iet.GeneralizedPermutation('a a','b b',reduced=True)1087sage: p._inversed()1088sage: p1089a a1090b b10911092::10931094sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True)1095sage: p._inversed()1096sage: p1097a b b1098c c a10991100::11011102sage: p = iet.GeneralizedPermutation('a a','b b c c',reduced=True)1103sage: p._inversed()1104sage: p1105a a b b1106c c1107"""1108self._twin = [self._twin[1], self._twin[0]]11091110for interval in (0,1):1111for j in xrange(self.length(interval)):1112self._twin[interval][j] = (1-self._twin[interval][j][0],1113self._twin[interval][j][1])11141115def rauzy_diagram(self, **kargs):1116r"""1117Returns the associated Rauzy diagram.11181119The Rauzy diagram of a permutation corresponds to all permutations1120that we could obtain from this one by Rauzy move. The set obtained1121is a labelled Graph. The label of vertices being 0 or 1 depending1122on the type.11231124OUTPUT:11251126Rauzy diagram -- the graph of permutations obtained by rauzy induction11271128EXAMPLES::11291130sage: p = iet.Permutation('a b c d', 'd a b c')1131sage: d = p.rauzy_diagram()1132"""1133return ReducedRauzyDiagram(self, **kargs)11341135def labelize_flip(couple):1136r"""1137Returns a string from a 2-uple couple of the form (name, flip).11381139TESTS::11401141sage: from sage.dynamics.interval_exchanges.reduced import labelize_flip1142sage: labelize_flip((4,1))1143' 4'1144sage: labelize_flip(('a',-1))1145'-a'1146"""1147if couple[1] == -1: return '-' + str(couple[0])1148return ' ' + str(couple[0])11491150class FlippedReducedPermutation(ReducedPermutation):1151r"""1152Flipped Reduced Permutation.11531154.. warning::11551156Internal class! Do not use directly!11571158INPUT:11591160- ``intervals`` - a list of two lists11611162- ``flips`` - the flipped letters11631164- ``alphabet`` - an alphabet1165"""1166def __init__(self, intervals=None, flips=None, alphabet=None):1167r"""1168TESTS::11691170sage: p = iet.Permutation('a b','b a',reduced=True,flips='a')1171sage: p == loads(dumps(p))1172True1173sage: p = iet.Permutation('a b','b a',reduced=True,flips='b')1174sage: p == loads(dumps(p))1175True1176sage: p = iet.Permutation('a b','b a',reduced=True,flips='ab')1177sage: p == loads(dumps(p))1178True1179sage: p = iet.GeneralizedPermutation('a a','b b',reduced=True,flips='a')1180sage: p == loads(dumps(p))1181True1182sage: p = iet.GeneralizedPermutation('a a','b b',reduced=True,flips='b')1183sage: p == loads(dumps(p))1184True1185sage: p = iet.GeneralizedPermutation('a a','b b',reduced=True,flips='ab')1186sage: p == loads(dumps(p))1187True1188"""1189self._hash = None11901191if intervals is None:1192self._twin = [[],[]]1193self._flips = [[],[]]1194self._alphabet = None11951196else:1197if flips is None: flips = []11981199if alphabet is None : self._init_alphabet(intervals)1200else : self._alphabet = Alphabet(alphabet)12011202self._init_twin(intervals)1203self._init_flips(intervals, flips)12041205self._hash = None12061207def __copy__(self):1208r"""1209Returns a copy of self.12101211TESTS::12121213sage: p = iet.GeneralizedPermutation('a a b', 'c c b',reduced=True, flips='a')1214sage: q = copy(p)1215sage: p == q1216True1217sage: p is q1218False1219"""1220p = self.__class__()12211222p._twin = [self._twin[0][:], self._twin[1][:]]1223p._flips = [self._flips[0][:], self._flips[1][:]]1224p._alphabet = self._alphabet1225p._repr_type = self._repr_type1226p._repr_options = self._repr_options12271228return p12291230def right_rauzy_move(self, winner):1231r"""1232Performs a Rauzy move on the right.12331234EXAMPLE::12351236sage: p = iet.Permutation('a b c','c b a',reduced=True,flips='c')1237sage: p.right_rauzy_move('top')1238-a b -c1239-a -c b1240"""1241winner = interval_conversion(winner)12421243result = copy(self)12441245loser_to = result._get_loser_to(winner)12461247result._flip_rauzy_move(winner, loser_to)1248result._twin_rauzy_move(winner, loser_to)12491250return result12511252def _reversed(self):1253r"""1254Reverses the permutation12551256TESTS:12571258::12591260sage: p = iet.Permutation('a b c d','c d b a',reduced=True,flips='a')1261sage: p1262-a b c d1263c d b -a1264sage: p._reversed()1265sage: p1266a b c -d1267-d c a b1268sage: p._reversed()1269sage: p1270-a b c d1271c d b -a12721273::12741275sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True,flips='a')1276sage: p1277-a -a b1278b c c1279sage: p._reversed()1280sage: p1281a -b -b1282c c a1283sage: p._reversed()1284sage: p1285-a -a b1286b c c1287"""1288super(FlippedReducedPermutation, self)._reversed()1289self._flips[0].reverse()1290self._flips[1].reverse()12911292def _inversed(self):1293r"""1294Inverses the permutation.12951296TESTS:12971298::12991300sage: p = iet.Permutation('a b c d','c d b a',flips='a')1301sage: p1302-a b c d1303c d b -a1304sage: p._inversed()1305sage: p1306c d b -a1307-a b c d1308sage: p._inversed()1309sage: p1310-a b c d1311c d b -a13121313::13141315sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True,flips='a')1316sage: p1317-a -a b1318b c c1319sage: p._inversed()1320sage: p1321a b b1322-c -c a1323sage: p._inversed()1324sage: p1325-a -a b1326b c c1327"""1328super(FlippedReducedPermutation, self)._inversed()1329self._flips.reverse()13301331class FlippedReducedPermutationIET(1332FlippedReducedPermutation,1333FlippedPermutationIET,1334ReducedPermutationIET):1335r"""1336Flipped Reduced Permutation from iet13371338EXAMPLES13391340::13411342sage: p = iet.Permutation('a b c', 'c b a', flips=['a'], reduced=True)1343sage: p.rauzy_move(1)1344-a -b c1345-a c -b13461347TESTS::13481349sage: p = iet.Permutation('a b','b a',flips=['a'])1350sage: p == loads(dumps(p))1351True1352"""1353def __cmp__(self, other):1354r"""1355Defines a natural lexicographic order.13561357TESTS::13581359sage: p = iet.Permutation('a b','a b',reduced=True,flips='a')1360sage: q = copy(p)1361sage: q.alphabet([0,1])1362sage: p == q1363True1364sage: l0 = ['a b','a b']1365sage: l1 = ['a b','b a']1366sage: l2 = ['b a', 'a b']1367sage: p0 = iet.Permutation(l0, reduced=True, flips='ab')1368sage: p1 = iet.Permutation(l1, reduced=True, flips='a')1369sage: p2 = iet.Permutation(l2, reduced=True, flips='b')1370sage: p3 = iet.Permutation(l1, reduced=True, flips='ab')1371sage: p4 = iet.Permutation(l2 ,reduced=True,flips='ab')1372sage: p0 == p1 or p0 == p2 or p0 == p3 or p0 == p41373False1374sage: p0 != p1 and p0 != p2 and p0 != p3 and p0 != p41375True1376sage: p1 == p2 and p3 == p41377True1378sage: p1 != p2 or p3 != p41379False1380sage: p1 == p3 or p1 == p4 or p2 == p3 or p2 == p41381False1382sage: p1 != p3 and p1 != p4 and p2 != p3 and p2 != p41383True1384sage: p1 = iet.Permutation(l1,reduced=True, flips='a')1385sage: p2 = iet.Permutation(l1,reduced=True, flips='b')1386sage: p3 = iet.Permutation(l1,reduced=True, flips='ab')1387sage: p2 > p3 and p3 < p21388True1389sage: p1 > p2 and p2 < p11390True1391sage: p1 > p3 and p3 < p11392True1393sage: q1 = iet.Permutation(l0, reduced=True, flips='a')1394sage: q2 = iet.Permutation(l0, reduced=True, flips='b')1395sage: q3 = iet.Permutation(l0, reduced=True, flips='ab')1396sage: q2 > q1 and q2 > q3 and q1 < q2 and q3 < q21397True1398sage: q1 > q31399True1400sage: q3 < q11401True1402sage: r = iet.Permutation('a b c','a b c', reduced=True, flips='a')1403sage: r > p1 and r > p2 and r > p31404True1405sage: p1 < r and p2 < r and p3 < r1406True1407"""1408if type(self) != type(other):1409return -114101411if len(self) > len(other):1412return 11413elif len(self) < len(other):1414return -114151416n = len(self)1417j = 01418while (j < n and1419self._twin[1][j] == other._twin[1][j] and1420self._flips[1][j] == other._flips[1][j]):1421j += 114221423if j != n:1424if self._twin[1][j] > other._twin[1][j]: return 11425elif self._twin[1][j] < other._twin[1][j]: return -11426else: return self._flips[1][j]14271428return 014291430def list(self, flips=False):1431r"""1432Returns a list representation of self.14331434INPUT:14351436- ``flips`` - boolean (default: False) if True the output contains14372-uple of (label, flip)14381439EXAMPLES:14401441::1442sage: p = iet.Permutation('a b','b a',reduced=True,flips='b')1443sage: p.list(flips=True)1444[[('a', 1), ('b', -1)], [('b', -1), ('a', 1)]]1445sage: p.list(flips=False)1446[['a', 'b'], ['b', 'a']]1447sage: p.alphabet([0,1])1448sage: p.list(flips=True)1449[[(0, 1), (1, -1)], [(1, -1), (0, 1)]]1450sage: p.list(flips=False)1451[[0, 1], [1, 0]]14521453One can recover the initial permutation from this list::14541455sage: p = iet.Permutation('a b','b a',reduced=True,flips='a')1456sage: iet.Permutation(p.list(), flips=p.flips(), reduced=True) == p1457True1458"""1459if flips:1460a0 = zip(map(self.alphabet().unrank, range(0,len(self))), self._flips[0])1461a1 = zip(map(self.alphabet().unrank, self._twin[1]), self._flips[1])14621463else:1464a0 = map(self.alphabet().unrank, range(0,len(self)))1465a1 = map(self.alphabet().unrank, self._twin[1])14661467return [a0,a1]14681469def _get_loser_to(self, winner) :1470r"""1471This function return the position of the future loser position.14721473TESTS:14741475::14761477sage: p = iet.GeneralizedPermutation('a b b','c c a', reduced=True, flips='ab')1478sage: p._get_loser_to(0)1479(0, 2)1480sage: p._get_loser_to(1)1481(0, 0)14821483::14841485sage: p = iet.GeneralizedPermutation('a a','b b c c',reduced=True,flips='a')1486sage: p._get_loser_to(0)1487(0, 1)1488"""1489if self._flips[winner][-1] == 1 :1490return (1-winner, self._twin[winner][-1]+1)1491else :1492return (1-winner, self._twin[winner][-1])14931494def _flip_rauzy_move(self, winner, loser_to):1495r"""1496Performs a Rauzy move on flips.14971498TESTS::14991500sage: p = iet.GeneralizedPermutation('a b b','c c a', reduced=True, flips='ab')1501sage: p1502-a -b -b1503c c -a1504sage: p.rauzy_move(1) #indirect doctest1505a -b a1506c c -b1507sage: p.rauzy_move(0) #indirect doctest1508a -b a -b1509c c1510"""1511loser = 1 - winner15121513loser_twin_interval, loser_twin_position = winner, self._twin[loser][-1]1514loser_interval_to, loser_position_to = loser_to15151516flip = self._flips[winner][-1] * self._flips[loser][-1]15171518self._flips[loser_twin_interval][loser_twin_position] = flip15191520del self._flips[loser][-1]1521self._flips[loser_interval_to].insert(loser_position_to, flip)15221523def rauzy_diagram(self, **kargs):1524r"""1525Returns the associated Rauzy diagram.15261527EXAMPLES::15281529sage: p = iet.Permutation('a b','b a',reduced=True,flips='a')1530sage: r = p.rauzy_diagram()1531sage: p in r1532True1533"""1534return FlippedReducedRauzyDiagram(self, **kargs)15351536class FlippedReducedPermutationLI(1537FlippedReducedPermutation,1538FlippedPermutationLI,1539ReducedPermutationLI):1540r"""1541Flipped Reduced Permutation from li15421543EXAMPLES:15441545Creation using the GeneralizedPermutation function::15461547sage: p = iet.GeneralizedPermutation('a a b', 'b c c', reduced=True, flips='a')1548"""1549def _get_loser_to(self, winner) :1550r"""1551This function return the position of the future loser position.15521553TESTS:15541555::15561557sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True,flips='b')1558sage: p._get_loser_to(0)1559(1, 0)1560sage: p._get_loser_to(1)1561(1, 1)15621563::15641565sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True,flips='c')1566sage: p._get_loser_to(0)1567(1, 1)1568sage: p._get_loser_to(1)1569(1, 2)1570"""1571loser = 1 - winner15721573if self._twin[winner][-1][0] == loser :1574if self._flips[winner][-1] == 1 :1575return (loser, self._twin[winner][-1][1] + 1)1576else :1577return (loser, self._twin[winner][-1][1])1578else :1579if self._flips[winner][-1] == 1 :1580return (winner, self._twin[winner][-1][1])1581else :1582return (winner, self._twin[winner][-1][1] + 1)15831584def _flip_rauzy_move(self, winner, loser_to):1585r"""1586Performs a Rauzy move on flips15871588TESTS::15891590sage: p = iet.GeneralizedPermutation('a a b','b c c',flips='b',reduced=True)1591sage: p1592a a -b1593-b c c1594sage: p.rauzy_move('top') #indirect doctest1595a a -b1596-c -b -c1597"""1598loser = 1 - winner15991600loser_twin_interval, loser_twin_position = self._twin[loser][-1]1601loser_interval_to, loser_position_to = loser_to16021603flip = self._flips[winner][-1] * self._flips[loser][-1]16041605self._flips[loser_twin_interval][loser_twin_position] = flip16061607del self._flips[loser][-1]1608self._flips[loser_interval_to].insert(loser_position_to, flip)16091610def list(self, flips=False):1611r"""1612Returns a list representation of self.16131614INPUT:16151616- ``flips`` - boolean (default: False) return the list with flips16171618EXAMPLES:16191620::16211622sage: p = iet.GeneralizedPermutation('a a','b b',reduced=True,flips='a')1623sage: p.list(flips=True)1624[[('a', -1), ('a', -1)], [('b', 1), ('b', 1)]]1625sage: p.list(flips=False)1626[['a', 'a'], ['b', 'b']]16271628sage: p = iet.GeneralizedPermutation('a a b','b c c',reduced=True,flips='abc')1629sage: p.list(flips=True)1630[[('a', -1), ('a', -1), ('b', -1)], [('b', -1), ('c', -1), ('c', -1)]]1631sage: p.list(flips=False)1632[['a', 'a', 'b'], ['b', 'c', 'c']]16331634one can rebuild the permutation from the list::16351636sage: p = iet.GeneralizedPermutation('a a b','b c c',flips='a',reduced=True)1637sage: iet.GeneralizedPermutation(p.list(),flips=p.flips(),reduced=True) == p1638True1639"""1640i_a = 01641l = [[False]*len(self._twin[0]), [False]*len(self._twin[1])]16421643if flips:1644for i in range(2): # False means empty here1645for j in range(len(l[i])):1646if l[i][j] is False:1647l[i][j] = (self._alphabet.unrank(i_a), self._flips[i][j])1648l[self._twin[i][j][0]][self._twin[i][j][1]] = l[i][j]1649i_a += 116501651else:1652for i in range(2): # False means empty here1653for j in range(len(l[i])):1654if l[i][j] is False:1655l[i][j] = self._alphabet.unrank(i_a)1656l[self._twin[i][j][0]][self._twin[i][j][1]] = l[i][j]1657i_a += 11658return l16591660def __eq__(self, other) :1661r"""1662TESTS::16631664sage: a0 = [0,0,1]1665sage: a1 = [1,2,2]1666sage: p = iet.GeneralizedPermutation(a0,a1,reduced=True,flips=[0])1667sage: q = copy(p)1668sage: q.alphabet("abc")1669sage: p == q1670True1671sage: b0 = [1,0,0]1672sage: b1 = [2,2,1]1673sage: r = iet.GeneralizedPermutation(b0,b1,reduced=True,flips=[0])1674sage: p == r or q == r1675False1676"""1677return (type(self) == type(other) and1678self._twin == other._twin and1679self._flips == other._flips)16801681def __ne__(self, other) :1682r"""1683TESTS::16841685sage: a0 = [0,0,1]1686sage: a1 = [1,2,2]1687sage: p = iet.GeneralizedPermutation(a0,a1,reduced=True,flips=[0])1688sage: q = copy(p)1689sage: q.alphabet("abc")1690sage: p != q1691False1692sage: b0 = [1,0,0]1693sage: b1 = [2,2,1]1694sage: r = iet.GeneralizedPermutation(b0,b1,reduced=True,flips=[0])1695sage: p != r and q != r1696True1697"""1698return (type(self) != type(other) or1699self._twin != other._twin or1700self._flips != other._flips)17011702def rauzy_diagram(self, **kargs):1703r"""1704Returns the associated Rauzy diagram.17051706For more explanation and a list of arguments try help(iet.RauzyDiagram)17071708EXAMPLES::17091710sage: p = iet.GeneralizedPermutation('a a b','c c b',reduced=True)1711sage: r = p.rauzy_diagram()1712sage: p in r1713True1714"""1715return FlippedReducedRauzyDiagram(self, **kargs)17161717class ReducedRauzyDiagram(RauzyDiagram):1718r"""1719Rauzy diagram of reduced permutations1720"""1721def _permutation_to_vertex(self, p):1722r"""1723The necessary data to store the permutation.17241725TESTS::172617271728sage: p = iet.Permutation('a b c','c b a',reduced=True) #indirect doctest1729sage: r = p.rauzy_diagram()1730sage: p in r1731True1732"""1733return (tuple(p._twin[0]), tuple(p._twin[1]))17341735def _set_element(self, data=None):1736r"""1737Sets self._element with data.17381739TESTS::17401741sage: p = iet.Permutation('a b c','c b a',reduced=True)1742sage: r = p.rauzy_diagram()1743sage: p in r #indirect doctest1744True1745"""1746self._element._twin = [list(data[0]), list(data[1])]17471748class FlippedReducedRauzyDiagram(FlippedRauzyDiagram, ReducedRauzyDiagram):1749r"""1750Rauzy diagram of flipped reduced permutations.1751"""1752def _permutation_to_vertex(self, p):1753r"""1754TESTS::17551756sage: p = iet.GeneralizedPermutation('a b b','c c a',flips='a',reduced=True)1757sage: r = p.rauzy_diagram()1758sage: p in r #indirect doctest1759True1760"""1761return ((tuple(p._twin[0]), tuple(p._twin[1])),1762(tuple(p._flips[0]), tuple(p._flips[1])))17631764def _set_element(self, data=None):1765r"""1766Sets self._element with data.1767TESTS::17681769sage: r = iet.RauzyDiagram('a b c','c b a',flips='b',reduced=True) #indirect doctest1770"""1771self._element._twin = [list(data[0][0]), list(data[0][1])]1772self._element._flips = [list(data[1][0]), list(data[1][1])]177317741775