Path: blob/master/src/sage/dynamics/interval_exchanges/labelled.py
8815 views
r"""1Labelled permutations23A labelled (generalized) permutation is better suited to study the4dynamic of a translation surface than a reduced one (see the module5:mod:`sage.dynamics.interval_exchanges.reduced`). The latter is more6adapted to the study of strata. This kind of permutation was7introduced by Yoccoz [Yoc05]_ (see also [MMY03]_).89In fact, there is a geometric counterpart of labelled10permutations. They correspond to translation surfaces with marked11outgoing separatrices (i.e. we fix a label for each of them).1213Remarks that Rauzy diagram of reduced objects are significantly14smaller than the one for labelled object (for the permutation a b d b15e / e d c a c the labelled Rauzy diagram contains 8760 permutations,16and the reduced only 73). But, as it is in geometrical way, the17labelled Rauzy diagram is a covering of the reduced Rauzy diagram.1819AUTHORS:2021- Vincent Delecroix (2009-09-29) : initial version2223TESTS::2425sage: from sage.dynamics.interval_exchanges.labelled import LabelledPermutationIET26sage: LabelledPermutationIET([['a', 'b', 'c'], ['c', 'b', 'a']])27a b c28c b a29sage: LabelledPermutationIET([[1,2,3,4],[4,1,2,3]])301 2 3 4314 1 2 332sage: from sage.dynamics.interval_exchanges.labelled import LabelledPermutationLI33sage: LabelledPermutationLI([[1,1],[2,2,3,3,4,4]])341 1352 2 3 3 4 436sage: LabelledPermutationLI([['a','a','b','b','c','c'],['d','d']])37a a b b c c38d d39sage: from sage.dynamics.interval_exchanges.labelled import FlippedLabelledPermutationIET40sage: FlippedLabelledPermutationIET([[1,2,3],[3,2,1]],flips=[1,2])41-1 -2 3423 -2 -143sage: FlippedLabelledPermutationIET([['a','b','c'],['b','c','a']],flips='b')44a -b c45-b c a46sage: from sage.dynamics.interval_exchanges.labelled import FlippedLabelledPermutationLI47sage: FlippedLabelledPermutationLI([[1,1],[2,2,3,3,4,4]], flips=[1,4])48-1 -1492 2 3 3 -4 -450sage: FlippedLabelledPermutationLI([['a','a','b','b'],['c','c']],flips='ac')51-a -a b b52-c -c53sage: from sage.dynamics.interval_exchanges.labelled import LabelledRauzyDiagram54sage: p = LabelledPermutationIET([[1,2,3],[3,2,1]])55sage: d1 = LabelledRauzyDiagram(p)56sage: p = LabelledPermutationIET([['a','b'],['b','a']])57sage: d = p.rauzy_diagram()58sage: g1 = d.path(p, 'top', 'bottom')59sage: g1.matrix()60[1 1]61[1 2]62sage: g2 = d.path(p, 'bottom', 'top')63sage: g2.matrix()64[2 1]65[1 1]66sage: p = LabelledPermutationIET([['a','b','c','d'],['d','c','b','a']])67sage: d = p.rauzy_diagram()68sage: g = d.path(p, 't', 't', 'b', 't', 'b', 'b', 't', 'b')69sage: g70Path of length 8 in a Rauzy diagram71sage: g.is_loop()72True73sage: g.is_full()74True75sage: s1 = g.orbit_substitution()76sage: s177WordMorphism: a->adbd, b->adbdbd, c->adccd, d->adcd78sage: s2 = g.interval_substitution()79sage: s280WordMorphism: a->abcd, b->bab, c->cdc, d->dcbababcd81sage: s1.incidence_matrix() == s2.incidence_matrix().transpose()82True8384REFERENCES:8586.. [Yoc05] Jean-Christophe Yoccoz "Echange d'Intervalles", Cours au college de87France8889.. [MMY03] Jean-Christophe Yoccoz, Stefano Marmi and Pierre Moussa "On the90cohomological equation for interval exchange maps", :arxiv:`math/0304469v1`91"""92#*****************************************************************************93# Copyright (C) 2008 Vincent Delecroix <[email protected]>94#95# Distributed under the terms of the GNU General Public License (GPL)96# http://www.gnu.org/licenses/97#*****************************************************************************9899from sage.structure.sage_object import SageObject100from sage.misc.lazy_attribute import lazy_attribute101102from copy import copy103104from sage.combinat.words.alphabet import Alphabet105from sage.combinat.words.morphism import WordMorphism106107from sage.matrix.constructor import identity_matrix108from sage.rings.integer import Integer109110from template import PermutationIET, PermutationLI111from template import FlippedPermutationIET, FlippedPermutationLI112from template import twin_list_iet, twin_list_li113from template import RauzyDiagram, FlippedRauzyDiagram114from template import interval_conversion, side_conversion115116class LabelledPermutation(SageObject):117r"""118General template for labelled objects.119120.. warning::121122Internal class! Do not use directly!123"""124def __init__(self, intervals=None, alphabet=None):125r"""126TESTS::127128sage: from sage.dynamics.interval_exchanges.labelled import LabelledPermutationIET129sage: p1 = LabelledPermutationIET([[1,2,3],[3,2,1]])130sage: p1 == loads(dumps(p1))131True132sage: p2 = LabelledPermutationIET([['a', 'b', 'c'], ['c', 'b', 'a']])133sage: p2 == loads(dumps(p2))134True135sage: p3 = LabelledPermutationIET([['1','2','3'],['3','2','1']])136sage: p3 == loads(dumps(p3))137True138sage: from sage.dynamics.interval_exchanges.labelled import LabelledPermutationLI139sage: p1 = LabelledPermutationLI([[1,2,2],[3,3,1]])140sage: p1 == loads(dumps(p1))141True142sage: p2 = LabelledPermutationLI([['a','b','b'],['c','c','a']])143sage: p2 == loads(dumps(p2))144True145sage: p3 = LabelledPermutationLI([['1','2','2'],['3','3','1']])146sage: p3 == loads(dumps(p3))147True148"""149self._hash = None150151if intervals is None:152self._intervals = [[],[]]153self._alphabet = None154155else:156if alphabet is not None:157alphabet = Alphabet(alphabet)158if alphabet.cardinality() < len(intervals[0]) :159raise ValueError("the alphabet is too short")160self._alphabet = alphabet161162else:163self._init_alphabet(intervals)164165self._intervals = [166map(self._alphabet.rank, intervals[0]),167map(self._alphabet.rank, intervals[1])]168169def __copy__(self):170r"""171Returns a copy of self.172173TESTS::174175sage: p = iet.Permutation('a b c','c b a')176sage: q = copy(p)177sage: p == q178True179sage: p is q180False181sage: p._inversed()182sage: p == q183False184sage: p._inversed()185sage: p == q186True187sage: p._reversed()188sage: p == q189False190sage: q._reversed()191sage: p == q192True193"""194result = self.__class__()195196result._intervals = [197copy(self._intervals[0]),198copy(self._intervals[1])]199200result._alphabet = self._alphabet201result._repr_type = self._repr_type202result._repr_options = self._repr_options203204return result205206def __len__(self):207r"""208TESTS::209210sage: len(iet.Permutation('',''))2110212sage: len(iet.Permutation('a','a'))2131214sage: len(iet.Permutation('1 2 3 4 5 6','1 2 3 4 5 6'))2156216"""217return (len(self._intervals[0]) + len(self._intervals[1])) / 2218219def length_top(self):220r"""221Returns the number of intervals in the top segment.222223OUTPUT:224225integer -- number of intervals226227EXAMPLES::228229sage: iet.Permutation('a b c','c b a').length_top()2303231sage: iet.GeneralizedPermutation('a a','b b c c').length_top()2322233sage: iet.GeneralizedPermutation('a a b b','c c').length_top()2344235"""236return len(self._intervals[0])237238def length_bottom(self):239r"""240Returns the number of intervals in the bottom segment.241242OUTPUT:243244integer -- number of intervals245246EXAMPLES::247248sage: iet.Permutation('a b','b a').length_bottom()2492250sage: iet.GeneralizedPermutation('a a','b b c c').length_bottom()2514252sage: iet.GeneralizedPermutation('a a b b','c c').length_bottom()2532254"""255return len(self._intervals[1])256257def length(self, interval=None):258r"""259Returns a 2-uple of lengths.260261p.length() is identical to (p.length_top(), p.length_bottom())262If an interval is specified, it returns the length of the specified263interval.264265INPUT:266267- ``interval`` - ``None``, 'top' or 'bottom'268269OUTPUT:270271tuple -- a 2-uple of integers272273EXAMPLES::274275sage: iet.Permutation('a b c','c b a').length()276(3, 3)277sage: iet.GeneralizedPermutation('a a','b b c c').length()278(2, 4)279sage: iet.GeneralizedPermutation('a a b b','c c').length()280(4, 2)281"""282if interval is None:283return len(self._intervals[0]),len(self._intervals[1])284else:285interval = interval_conversion(interval)286return len(self._intervals[interval])287288def __getitem__(self,i):289r"""290TESTS::291292sage: p = iet.Permutation([0,1,2,3],[3,2,1,0])293sage: p[0][0]2940295sage: p[1][2]2961297sage: p = iet.Permutation('a b c','c b a')298sage: p[0][1]299'b'300sage: p[1][2]301'a'302"""303return map(self._alphabet.unrank, self._intervals[i])304305def __hash__(self):306r"""307ALGORITHM:308309Uses the hash of string310311TESTS::312313sage: from sage.dynamics.interval_exchanges.labelled import *314sage: p1 = LabelledPermutationIET([[1,2],[1,2]])315sage: p2 = LabelledPermutationIET([[1,2],[2,1]])316sage: p3 = LabelledPermutationLI([[1,1],[2,2]])317sage: hash(p1) == hash(p2)318False319sage: hash(p1) == hash(p3)320False321sage: hash(p2) == hash(p3)322False323sage: p1 = LabelledPermutationLI([[1,1], [2,2,3,3]])324sage: p2 = LabelledPermutationLI([[1,1,2], [2,3,3]])325sage: p3 = LabelledPermutationLI([[1,1,2,2], [3,3]])326sage: hash(p1) == hash(p2)327False328sage: hash(p1) == hash(p3)329False330sage: hash(p2) == hash(p3)331False332"""333if self._hash is None:334t = []335t.extend([str(i) for i in self._intervals[0]])336t.extend([str(-(i+1)) for i in self._intervals[1]])337self._hash = hash(''.join(t))338return self._hash339340def _reversed(self):341r"""342.. TODO::343344resolve properly the mutablility problem with the345:meth:`_twin` attribute.346347TESTS::348349sage: p = iet.Permutation([1,2,3],[3,1,2])350sage: p3511 2 33523 1 2353sage: p._reversed()354sage: p3553 2 13562 1 3357"""358if self.__dict__.has_key('_twin'):359del self.__dict__['_twin']360if self._hash is not None:361self._hash = None362363self._intervals[0].reverse()364self._intervals[1].reverse()365366def _inversed(self):367r"""368.. TODO::369370properly resolve the mutability problem of the twin371372TESTS::373374sage: p = iet.Permutation([1,2,3],[3,1,2])375sage: p3761 2 33773 1 2378sage: p._inversed()379sage: p3803 1 23811 2 3382"""383if self.__dict__.has_key('_twin'):384del self.__dict__['_twin']385if self._hash is not None:386self._hash = None387388self._intervals = (self._intervals[1],self._intervals[0])389390def list(self):391r"""392Returns a list of two lists corresponding to the intervals.393394OUTPUT:395396list -- two lists of labels397398EXAMPLES:399400The list of an permutation from iet::401402sage: p1 = iet.Permutation('1 2 3', '3 1 2')403sage: p1.list()404[['1', '2', '3'], ['3', '1', '2']]405sage: p1.alphabet("abc")406sage: p1.list()407[['a', 'b', 'c'], ['c', 'a', 'b']]408409Recovering the permutation from this list (and the alphabet)::410411sage: q1 = iet.Permutation(p1.list(),alphabet=p1.alphabet())412sage: p1 == q1413True414415The list of a quadratic permutation::416417sage: p2 = iet.GeneralizedPermutation('g o o', 'd d g')418sage: p2.list()419[['g', 'o', 'o'], ['d', 'd', 'g']]420421Recovering the permutation::422423sage: q2 = iet.GeneralizedPermutation(p2.list(),alphabet=p2.alphabet())424sage: p2 == q2425True426"""427a0 = map(self._alphabet.unrank, self._intervals[0])428a1 = map(self._alphabet.unrank, self._intervals[1])429return [a0, a1]430431def erase_letter(self, letter):432r"""433Return the permutation with the specified letter removed.434435OUTPUT:436437permutation -- the resulting permutation438439EXAMPLES:440441::442443sage: p = iet.Permutation('a b c d','c d b a')444sage: p.erase_letter('a')445b c d446c d b447sage: p.erase_letter('b')448a c d449c d a450sage: p.erase_letter('c')451a b d452d b a453sage: p.erase_letter('d')454a b c455c b a456457::458459sage: p = iet.GeneralizedPermutation('a b b','c c a')460sage: p.erase_letter('a')461b b462c c463464Beware, there is no validity check for permutation from linear465involutions::466467sage: p = iet.GeneralizedPermutation('a b b','c c a')468sage: p.erase_letter('b')469a470c c a471"""472l = [[], []]473letters = self.letters()474a = letters.index(letter)475476for i in (0, 1):477for b in self._intervals[i]:478if b < a:479l[i].append(b)480elif b > a:481l[i].append(b-1)482483res = copy(self)484res._intervals = l485res.alphabet(letters[0:a] + letters[a+1:])486487return res488489def rauzy_move_matrix(self, winner=None, side='right'):490r"""491Returns the Rauzy move matrix.492493This matrix corresponds to the action of a Rauzy move on the494vector of lengths. By convention (to get a positive matrix),495the matrix is defined as the inverse transformation on the496length vector.497498OUTPUT:499500matrix -- a square matrix of positive integers501502EXAMPLES:503504::505506sage: p = iet.Permutation('a b','b a')507sage: p.rauzy_move_matrix('t')508[1 0]509[1 1]510sage: p.rauzy_move_matrix('b')511[1 1]512[0 1]513514::515516sage: p = iet.Permutation('a b c d','b d a c')517sage: q = p.left_right_inverse()518sage: m0 = p.rauzy_move_matrix(winner='top',side='right')519sage: n0 = q.rauzy_move_matrix(winner='top',side='left')520sage: m0 == n0521True522sage: m1 = p.rauzy_move_matrix(winner='bottom',side='right')523sage: n1 = q.rauzy_move_matrix(winner='bottom',side='left')524sage: m1 == n1525True526"""527if winner is None and side is None:528return identity_matrix(len(self))529530winner = interval_conversion(winner)531side = side_conversion(side)532533winner_letter = self._intervals[winner][side]534loser_letter = self._intervals[1-winner][side]535536m = copy(identity_matrix(len(self)))537m[winner_letter, loser_letter] = 1538539return m540541def rauzy_move_winner(self, winner=None, side=None):542r"""543Returns the winner of a Rauzy move.544545INPUT:546547- ``winner`` - either 'top' or 'bottom' ('t' or 'b' for short)548549- ``side`` - either 'left' or 'right' ('l' or 'r' for short)550551OUTPUT:552553-- a label554555EXAMPLES:556557::558559sage: p = iet.Permutation('a b c d','b d a c')560sage: p.rauzy_move_winner('top','right')561'd'562sage: p.rauzy_move_winner('bottom','right')563'c'564sage: p.rauzy_move_winner('top','left')565'a'566sage: p.rauzy_move_winner('bottom','left')567'b'568569::570571sage: p = iet.GeneralizedPermutation('a b b c','d c a e d e')572sage: p.rauzy_move_winner('top','right')573'c'574sage: p.rauzy_move_winner('bottom','right')575'e'576sage: p.rauzy_move_winner('top','left')577'a'578sage: p.rauzy_move_winner('bottom','left')579'd'580"""581if winner is None and side is None:582return None583584winner = interval_conversion(winner)585side = side_conversion(side)586587return self[winner][side]588589def rauzy_move_loser(self,winner=None,side=None):590r"""591Returns the loser of a Rauzy move592593INPUT:594595- ``winner`` - either 'top' or 'bottom' ('t' or 'b' for short)596597- ``side`` - either 'left' or 'right' ('l' or 'r' for short)598599OUTPUT:600601-- a label602603EXAMPLES::604605sage: p = iet.Permutation('a b c d','b d a c')606sage: p.rauzy_move_loser('top','right')607'c'608sage: p.rauzy_move_loser('bottom','right')609'd'610sage: p.rauzy_move_loser('top','left')611'b'612sage: p.rauzy_move_loser('bottom','left')613'a'614"""615if winner is None and side is None:616return None617618winner = interval_conversion(winner)619side = side_conversion(side)620621return self[1-winner][side]622623def LabelledPermutationsIET_iterator(nintervals=None,624irreducible=True,625alphabet=None):626r"""627Returns an iterator over labelled permutations.628629INPUT:630631- ``nintervals`` - integer or ``None``632633- ``irreducible`` - boolean (default: ``True``)634635- ``alphabet`` - something that should be converted to an alphabet636of at least nintervals letters637638OUTPUT:639640iterator -- an iterator over permutations641642TESTS::643644sage: for p in iet.Permutations_iterator(2, alphabet="ab"):645....: print p, "\n****" #indirect doctest646a b647b a648****649b a650a b651****652sage: for p in iet.Permutations_iterator(3, alphabet="abc"):653....: print p, "\n*****" #indirect doctest654a b c655b c a656*****657a b c658c a b659*****660a b c661c b a662*****663a c b664b a c665*****666a c b667b c a668*****669a c b670c b a671*****672b a c673a c b674*****675b a c676c a b677*****678b a c679c b a680*****681b c a682a b c683*****684b c a685a c b686*****687b c a688c a b689*****690c a b691a b c692*****693c a b694b a c695*****696c a b697b c a698*****699c b a700a b c701*****702c b a703a c b704*****705c b a706b a c707*****708"""709from itertools import imap, ifilter, product710from sage.combinat.permutation import Permutations711712if not irreducible:713if nintervals is None:714raise ValueError("choose a number of intervals")715716nintervals = Integer(nintervals)717718if not(nintervals > 0):719raise ValueError("nintervals must be positive")720721f = lambda x: LabelledPermutationIET([list(x[0]),list(x[1])],alphabet=alphabet)722723alphabet = Alphabet(alphabet)724g = lambda x: [alphabet.unrank(k-1) for k in x]725P = map(g, Permutations(nintervals))726return imap(f,product(P,P))727else:728return ifilter(729lambda x: x.is_irreducible(),730LabelledPermutationsIET_iterator(nintervals,False,alphabet))731732class LabelledPermutationIET(LabelledPermutation, PermutationIET):733"""734Labelled permutation for iet735736EXAMPLES:737738Reducibility testing::739740sage: p = iet.Permutation('a b c', 'c b a')741sage: p.is_irreducible()742True743744sage: q = iet.Permutation('a b c d', 'b a d c')745sage: q.is_irreducible()746False747748Rauzy movability and Rauzy move::749750sage: p = iet.Permutation('a b c', 'c b a')751sage: p.has_rauzy_move('top')752True753sage: print p.rauzy_move('bottom')754a c b755c b a756sage: p.has_rauzy_move('top')757True758sage: print p.rauzy_move('top')759a b c760c a b761762Rauzy diagram::763764sage: p = iet.Permutation('a b c', 'c b a')765sage: d = p.rauzy_diagram()766sage: p in d767True768"""769def __cmp__(self, other):770r"""771ALGORITHM:772773The order is lexicographic on intervals[0] + intervals[1]774775TESTS::776sage: list_of_p2 = []777sage: p0 = iet.Permutation('1 2', '1 2')778sage: p1 = iet.Permutation('1 2', '2 1')779sage: p0 != p0780False781sage: (p0 == p0) and (p0 < p1)782True783sage: (p1 > p0) and (p1 == p1)784True785"""786if type(self) != type(other):787return -1788789n = len(self)790if n != len(other):791return n - len(other)792793i, j = 0, 0794while (self._intervals[i][j] == other._intervals[i][j]):795j += 1796if j == n:797if i == 1: return 0798i = 1799j = 0800return self._intervals[i][j] - other._intervals[i][j]801802@lazy_attribute803def _twin(self):804r"""805The twin relations of the permutation.806807TESTS::808sage: p = iet.Permutation('a b','a b')809sage: p._twin810[[0, 1], [0, 1]]811sage: p = iet.Permutation('a b','b a')812sage: p._twin813[[1, 0], [1, 0]]814"""815return twin_list_iet(self._intervals)816817def reduced(self):818r"""819Returns the associated reduced abelian permutation.820821OUTPUT:822823a reduced permutation -- the underlying reduced permutation824825826EXAMPLES::827828sage: p = iet.Permutation("a b c d","d c a b")829sage: q = iet.Permutation("a b c d","d c a b",reduced=True)830sage: p.reduced() == q831True832"""833from reduced import ReducedPermutationIET834835return ReducedPermutationIET(self.list(), alphabet=self._alphabet)836837def is_identity(self):838r"""839Returns True if self is the identity.840841OUTPUT:842843bool -- True if self corresponds to the identity844845EXAMPLES::846847sage: iet.Permutation("a b","a b").is_identity()848True849sage: iet.Permutation("a b","b a").is_identity()850False851"""852for i in range(len(self)):853if self._intervals[0][i] != self._intervals[1][i]:854return False855return True856857def has_rauzy_move(self, winner=None, side=None):858r"""859Returns ``True`` if you can perform a Rauzy move.860861INPUT:862863- ``winner`` - the winner interval ('top' or 'bottom')864865- ``side`` - (default: 'right') the side ('left' or 'right')866867OUTPUT:868869bool -- ``True`` if self has a Rauzy move870871EXAMPLES:872873::874875sage: p = iet.Permutation('a b','b a')876sage: p.has_rauzy_move()877True878879::880881sage: p = iet.Permutation('a b c','b a c')882sage: p.has_rauzy_move()883False884"""885if side is None:886side = -1887else:888side = side_conversion(side)889890if not winner is None:891winner = interval_conversion(winner)892893return self._intervals[0][side] != self._intervals[1][side]894895def rauzy_move(self, winner=None, side=None, iteration=1):896r"""897Returns the Rauzy move.898899INPUT:900901- ``winner`` - the winner interval ('top' or 'bottom')902903- ``side`` - (default: 'right') the side ('left' or 'right')904905OUTPUT:906907permutation -- the Rauzy move of the permutation908909EXAMPLES:910911::912913sage: p = iet.Permutation('a b','b a')914sage: p.rauzy_move('t','right')915a b916b a917sage: p.rauzy_move('b','right')918a b919b a920921::922923sage: p = iet.Permutation('a b c','c b a')924sage: p.rauzy_move('t','right')925a b c926c a b927sage: p.rauzy_move('b','right')928a c b929c b a930931::932933sage: p = iet.Permutation('a b','b a')934sage: p.rauzy_move('t','left')935a b936b a937sage: p.rauzy_move('b','left')938a b939b a940941::942943sage: p = iet.Permutation('a b c','c b a')944sage: p.rauzy_move('t','left')945a b c946b c a947sage: p.rauzy_move('b','left')948b a c949c b a950"""951side = side_conversion(side)952winner = interval_conversion(winner)953954result = copy(self)955956for i in range(iteration):957winner_letter = result._intervals[winner][side]958loser_letter = result._intervals[1-winner].pop(side)959960loser_to = result._intervals[1-winner].index(winner_letter) - side961result._intervals[1-winner].insert(loser_to, loser_letter)962963return result964965def rauzy_move_interval_substitution(self,winner=None,side=None):966r"""967Returns the interval substitution associated.968969INPUT:970971- ``winner`` - the winner interval ('top' or 'bottom')972973- ``side`` - (default: 'right') the side ('left' or 'right')974975OUTPUT:976977WordMorphism -- a substitution on the alphabet of the permutation978979EXAMPLES::980981sage: p = iet.Permutation('a b','b a')982sage: p.rauzy_move_interval_substitution('top','right')983WordMorphism: a->a, b->ba984sage: p.rauzy_move_interval_substitution('bottom','right')985WordMorphism: a->ab, b->b986sage: p.rauzy_move_interval_substitution('top','left')987WordMorphism: a->ba, b->b988sage: p.rauzy_move_interval_substitution('bottom','left')989WordMorphism: a->a, b->ab990"""991d = dict([(letter,letter) for letter in self.letters()])992993if winner is None and side is None:994return WordMorphism(d)995996winner = interval_conversion(winner)997side = side_conversion(side)998999winner_letter = self.rauzy_move_winner(winner,side)1000loser_letter = self.rauzy_move_loser(winner,side)10011002if side == 0:1003d[winner_letter] = [loser_letter,winner_letter]1004else:1005d[winner_letter] = [winner_letter,loser_letter]10061007return WordMorphism(d)10081009def rauzy_move_orbit_substitution(self,winner=None,side=None):1010r"""1011Return the action of the rauzy_move on the orbit.10121013INPUT:10141015- ``i`` - integer10161017- ``winner`` - the winner interval ('top' or 'bottom')10181019- ``side`` - (default: 'right') the side ('right' or 'left')10201021OUTPUT:10221023WordMorphism -- a substitution on the alphabet of self10241025EXAMPLES::10261027sage: p = iet.Permutation('a b','b a')1028sage: p.rauzy_move_orbit_substitution('top','right')1029WordMorphism: a->ab, b->b1030sage: p.rauzy_move_orbit_substitution('bottom','right')1031WordMorphism: a->a, b->ab1032sage: p.rauzy_move_orbit_substitution('top','left')1033WordMorphism: a->a, b->ba1034sage: p.rauzy_move_orbit_substitution('bottom','left')1035WordMorphism: a->ba, b->b1036"""1037d = dict([(letter,letter) for letter in self.letters()])10381039if winner is None and side is None:1040return WordMorphism(d)10411042winner = interval_conversion(winner)1043side = side_conversion(side)104410451046loser_letter = self.rauzy_move_loser(winner,side)10471048top_letter = self.alphabet().unrank(self._intervals[0][side])1049bottom_letter = self.alphabet().unrank(self._intervals[1][side])10501051d[loser_letter] = [bottom_letter,top_letter]10521053return WordMorphism(d)10541055def rauzy_diagram(self, **args):1056"""1057Returns the associated Rauzy diagram.10581059For more information try help(iet.RauzyDiagram).10601061OUTPUT:10621063Rauzy diagram -- the Rauzy diagram of the permutation10641065EXAMPLES::10661067sage: p = iet.Permutation('a b c', 'c b a')1068sage: d = p.rauzy_diagram()1069"""1070return LabelledRauzyDiagram(self, **args)10711072class LabelledPermutationLI(LabelledPermutation, PermutationLI):1073r"""1074Labelled quadratic (or generalized) permutation10751076EXAMPLES:10771078Reducibility testing::10791080sage: p = iet.GeneralizedPermutation('a b b', 'c c a')1081sage: p.is_irreducible()1082True10831084Reducibility testing with associated decomposition::10851086sage: p = iet.GeneralizedPermutation('a b c a', 'b d d c')1087sage: p.is_irreducible()1088False1089sage: test, decomposition = p.is_irreducible(return_decomposition = True)1090sage: print test1091False1092sage: print decomposition1093(['a'], ['c', 'a'], [], ['c'])10941095Rauzy movability and Rauzy move::10961097sage: p = iet.GeneralizedPermutation('a a b b c c', 'd d')1098sage: p.has_rauzy_move(0)1099False1100sage: p.has_rauzy_move(1)1101True1102sage: q = p.rauzy_move(1)1103sage: print q1104a a b b c1105c d d1106sage: q.has_rauzy_move(0)1107True1108sage: q.has_rauzy_move(1)1109True11101111Rauzy diagrams::11121113sage: p = iet.GeneralizedPermutation('0 0 1 1','2 2')1114sage: r = p.rauzy_diagram()1115sage: p in r1116True1117"""1118def __cmp__(self, other):1119r"""1120ALGORITHM:11211122Order is lexicographic on length of intervals and on intervals.11231124TESTS::1125sage: p0 = iet.GeneralizedPermutation('0 0','1 1 2 2')1126sage: p1 = iet.GeneralizedPermutation('0 0','1 2 1 2')1127sage: p2 = iet.GeneralizedPermutation('0 0','1 2 2 1')1128sage: p3 = iet.GeneralizedPermutation('0 0 1','1 2 2')1129sage: p4 = iet.GeneralizedPermutation('0 0 1 1','2 2')1130sage: p5 = iet.GeneralizedPermutation('0 1 0 1','2 2')1131sage: p6 = iet.GeneralizedPermutation('0 1 1 0','2 2')1132sage: p0 == p0 and p0 < p1 and p0 < p2 and p0 < p3 and p0 < p41133True1134sage: p0 < p5 and p0 < p6 and p1 < p2 and p1 < p3 and p1 < p41135True1136sage: p1 < p5 and p1 < p6 and p2 < p3 and p2 < p4 and p2 < p51137True1138sage: p2 < p6 and p3 < p4 and p3 < p5 and p3 < p6 and p4 < p51139True1140sage: p4 < p6 and p5 < p6 and p0 == p0 and p1 == p1 and p2 == p21141True1142sage: p3 == p3 and p4 == p4 and p5 == p5 and p6 == p61143True1144"""1145if type(self) != type(other):1146return -111471148n = len(self)11491150if n != len(other): return n - len(other)11511152l0 = self._intervals[0]1153l1 = other._intervals[0]11541155n = len(self._intervals[0])11561157if n != len(other._intervals[0]): return n - len(other._intervals[0])11581159i = 01160while (i < n) and (l0[i] == l1[i]):1161i += 111621163if i != n:1164return l0[i] - l1[i]11651166l0 = self._intervals[1]1167l1 = other._intervals[1]1168n = len(self._intervals[1])11691170i = 01171while (i < n) and (l0[i] == l1[i]):1172i += 111731174if i != n:1175return l0[i] - l1[i]11761177return 011781179def has_right_rauzy_move(self, winner):1180r"""1181Test of Rauzy movability with a specified winner11821183A quadratic (or generalized) permutation is rauzy_movable type1184depending on the possible length of the last interval. It is1185dependent of the length equation.11861187INPUT:11881189- ``winner`` - 'top' (or 't' or 0) or 'bottom' (or 'b' or 1)11901191OUTPUT:11921193bool -- ``True`` if self has a Rauzy move11941195EXAMPLES:11961197::11981199sage: p = iet.GeneralizedPermutation('a a','b b')1200sage: p.has_right_rauzy_move('top')1201False1202sage: p.has_right_rauzy_move('bottom')1203False12041205::12061207sage: p = iet.GeneralizedPermutation('a a b','b c c')1208sage: p.has_right_rauzy_move('top')1209True1210sage: p.has_right_rauzy_move('bottom')1211True12121213::12141215sage: p = iet.GeneralizedPermutation('a a','b b c c')1216sage: p.has_right_rauzy_move('top')1217True1218sage: p.has_right_rauzy_move('bottom')1219False12201221::12221223sage: p = iet.GeneralizedPermutation('a a b b','c c')1224sage: p.has_right_rauzy_move('top')1225False1226sage: p.has_right_rauzy_move('bottom')1227True1228"""1229winner = interval_conversion(winner)1230loser = self._intervals[1-winner][-1]12311232# the same letter at the right-end (False)1233if self._intervals[0][-1] == self._intervals[1][-1] :1234return False12351236# the winner (or loser) letter is repeated on the other interval (True)1237if self._intervals[0][-1] in self._intervals[1]: return True1238if self._intervals[1][-1] in self._intervals[0]: return True12391240# the loser letters is the only letter repeated in the loser1241# interval (False)1242for i,c in enumerate((self._intervals[1-winner])):1243if c != loser and c in self._intervals[1-winner][i+1:]:1244return True12451246return False12471248def right_rauzy_move(self, winner):1249r"""1250Perform a Rauzy move on the right (the standard one).12511252INPUT:12531254- ``winner`` - 'top' (or 't' or 0) or 'bottom' (or 'b' or 1)12551256OUTPUT:12571258boolean -- ``True`` if self has a Rauzy move12591260EXAMPLES:12611262::12631264sage: p = iet.GeneralizedPermutation('a a b','b c c')1265sage: p.right_rauzy_move(0)1266a a b1267b c c1268sage: p.right_rauzy_move(1)1269a a1270b b c c12711272::12731274sage: p = iet.GeneralizedPermutation('a b b','c c a')1275sage: p.right_rauzy_move(0)1276a a b b1277c c1278sage: p.right_rauzy_move(1)1279a b b1280c c a12811282TESTS::12831284sage: p = iet.GeneralizedPermutation('a a b','b c c')1285sage: q = p.top_bottom_inverse()1286sage: q = q.right_rauzy_move(0)1287sage: q = q.top_bottom_inverse()1288sage: q == p.right_rauzy_move(1)1289True1290sage: q = p.top_bottom_inverse()1291sage: q = q.right_rauzy_move(1)1292sage: q = q.top_bottom_inverse()1293sage: q == p.right_rauzy_move(0)1294True1295sage: p = p.left_right_inverse()1296sage: q = q.left_rauzy_move(0)1297sage: q = q.left_right_inverse()1298sage: q == p.right_rauzy_move(0)1299True1300sage: q = p.left_right_inverse()1301sage: q = q.left_rauzy_move(1)1302sage: q = q.left_right_inverse()1303sage: q == p.right_rauzy_move(1)1304True1305"""1306result = copy(self)13071308winner_letter = result._intervals[winner][-1]1309loser_letter = result._intervals[1-winner].pop(-1)13101311if winner_letter in result._intervals[winner][:-1]:1312loser_to = result._intervals[winner].index(winner_letter)1313result._intervals[winner].insert(loser_to, loser_letter)1314else:1315loser_to = result._intervals[1-winner].index(winner_letter) + 11316result._intervals[1-winner].insert(loser_to, loser_letter)13171318return result13191320def left_rauzy_move(self, winner):1321r"""1322Perform a Rauzy move on the left.13231324INPUT:13251326- ``winner`` - 'top' or 'bottom'13271328OUTPUT:13291330permutation -- the Rauzy move of self13311332EXAMPLES:13331334::13351336sage: p = iet.GeneralizedPermutation('a a b','b c c')1337sage: p.left_rauzy_move(0)1338a a b b1339c c1340sage: p.left_rauzy_move(1)1341a a b1342b c c13431344::13451346sage: p = iet.GeneralizedPermutation('a b b','c c a')1347sage: p.left_rauzy_move(0)1348a b b1349c c a1350sage: p.left_rauzy_move(1)1351b b1352c c a a135313541355TESTS::13561357sage: p = iet.GeneralizedPermutation('a a b','b c c')1358sage: q = p.top_bottom_inverse()1359sage: q = q.left_rauzy_move(0)1360sage: q = q.top_bottom_inverse()1361sage: q == p.left_rauzy_move(1)1362True1363sage: q = p.top_bottom_inverse()1364sage: q = q.left_rauzy_move(1)1365sage: q = q.top_bottom_inverse()1366sage: q == p.left_rauzy_move(0)1367True1368sage: q = p.left_right_inverse()1369sage: q = q.right_rauzy_move(0)1370sage: q = q.left_right_inverse()1371sage: q == p.left_rauzy_move(0)1372True1373sage: q = p.left_right_inverse()1374sage: q = q.right_rauzy_move(1)1375sage: q = q.left_right_inverse()1376sage: q == p.left_rauzy_move(1)1377True1378"""1379result = copy(self)13801381winner_letter = result._intervals[winner][0]1382loser_letter = result._intervals[1-winner].pop(0)13831384if winner_letter in result._intervals[winner][1:]:1385loser_to = result._intervals[winner][1:].index(winner_letter)+21386result._intervals[winner].insert(loser_to, loser_letter)13871388else:1389loser_to = result._intervals[1-winner].index(winner_letter)1390result._intervals[1-winner].insert(loser_to, loser_letter)13911392return result13931394def reduced(self):1395r"""1396Returns the associated reduced quadratic permutations.13971398OUTPUT:13991400permutation -- the underlying reduced permutation14011402EXAMPLES::14031404sage: p = iet.GeneralizedPermutation('a a','b b c c')1405sage: q = p.reduced()1406sage: q1407a a1408b b c c1409sage: p.rauzy_move(0).reduced() == q.rauzy_move(0)1410True1411"""1412from reduced import ReducedPermutationLI14131414return ReducedPermutationLI(self.list(),alphabet=self._alphabet)14151416def rauzy_diagram(self, **kargs):1417r"""1418Returns the associated RauzyDiagram.14191420OUTPUT:14211422Rauzy diagram -- the Rauzy diagram of the permutation14231424EXAMPLES::14251426sage: p = iet.GeneralizedPermutation('a b c b', 'c d d a')1427sage: d = p.rauzy_diagram()1428sage: p in d1429True14301431For more information, try help(iet.RauzyDiagram)1432"""1433return LabelledRauzyDiagram(self, **kargs)14341435@lazy_attribute1436def _twin(self):1437r"""1438The twin list of the permutation14391440TEST::14411442sage: p = iet.GeneralizedPermutation('a a','b b')1443sage: p._twin1444[[(0, 1), (0, 0)], [(1, 1), (1, 0)]]1445"""1446return twin_list_li(self._intervals)14471448class FlippedLabelledPermutation(LabelledPermutation):1449r"""1450General template for labelled objects14511452.. warning::14531454Internal class! Do not use directly!1455"""1456def __init__(self, intervals=None, alphabet=None, flips=None):1457r"""1458INPUT:14591460- `intervals` - the intervals as a list of two lists14611462- `alphabet` - something that should be converted to an alphabe14631464- `flips` - a list of letters of the alphabet14651466TESTS:14671468::14691470sage: from sage.dynamics.interval_exchanges.labelled import FlippedLabelledPermutationIET1471sage: p = FlippedLabelledPermutationIET([['a','b'],['a','b']],flips='a')1472sage: p == loads(dumps(p))1473True1474sage: p = FlippedLabelledPermutationIET([['a','b'],['b','a']],flips='ab')1475sage: p == loads(dumps(p))1476True14771478::14791480sage: from sage.dynamics.interval_exchanges.labelled import FlippedLabelledPermutationLI1481sage: p = FlippedLabelledPermutationLI([['a','a','b'],['b','c','c']],flips='a')1482sage: p == loads(dumps(p))1483True1484sage: p = FlippedLabelledPermutationLI([['a','a'],['b','b','c','c']],flips='ac')1485sage: p == loads(dumps(p))1486True1487"""1488if intervals is None:1489intervals = [[], []]1490if flips is None: flips = []14911492super(FlippedLabelledPermutation, self).__init__(intervals, alphabet)1493self._init_flips(intervals, flips)14941495def __copy__(self):1496r"""1497Returns a copy of ``self``14981499TESTS::15001501sage: p = iet.Permutation('a b c','c b a',flips='a')1502sage: h = hash(p)1503sage: t = p._twin1504sage: q = copy(p)1505sage: q == p1506True1507sage: q is p1508False1509sage: q._twin is p._twin1510False1511"""1512result = self.__class__()15131514result._intervals = [self._intervals[0][:],1515self._intervals[1][:]]1516result._flips = [self._flips[0][:],1517self._flips[1][:]]15181519result._alphabet = self._alphabet1520result._repr_type = self._repr_type1521result._repr_options = self._repr_options15221523return result15241525def list(self, flips=False):1526r"""1527Returns a list associated to the permutation.15281529INPUT:15301531- ``flips`` - boolean (default: ``False``)15321533OUTPUT:15341535list -- two lists of labels15361537EXAMPLES::15381539sage: p = iet.GeneralizedPermutation('0 0 1 2 2 1', '3 3', flips='1')1540sage: p.list(flips=True)1541[[('0', 1), ('0', 1), ('1', -1), ('2', 1), ('2', 1), ('1', -1)], [('3', 1), ('3', 1)]]1542sage: p.list(flips=False)1543[['0', '0', '1', '2', '2', '1'], ['3', '3']]15441545The list can be used to reconstruct the permutation15461547::15481549sage: p = iet.Permutation('a b c','c b a',flips='ab')1550sage: p == iet.Permutation(p.list(), flips=p.flips())1551True15521553::15541555sage: p = iet.GeneralizedPermutation('a b b c','c d d a',flips='ad')1556sage: p == iet.GeneralizedPermutation(p.list(),flips=p.flips())1557True1558"""1559if flips:1560a0 = zip(map(self._alphabet.unrank, self._intervals[0]), self._flips[0])1561a1 = zip(map(self._alphabet.unrank, self._intervals[1]), self._flips[1])1562else:1563a0 = map(self._alphabet.unrank, self._intervals[0])1564a1 = map(self._alphabet.unrank, self._intervals[1])15651566return [a0,a1]15671568def __getitem__(self,i):1569r"""1570Get labels and flips of specified interval.15711572The result is a 2-uple (letter, flip) where letter is the name of the1573sub-interval and flip is a number corresponding to the presence of flip1574as following: 1 (no flip) and -1 (a flip).15751576EXAMPLES::15771578sage: p = iet.Permutation('a b', 'b a', flips='a')1579sage: print p[0]1580[('a', -1), ('b', 1)]1581sage: p = iet.GeneralizedPermutation('c p p', 't t c', flips='ct')1582sage: print p[1]1583[('t', -1), ('t', -1), ('c', -1)]1584"""1585if not isinstance(i, (Integer, int)):1586raise TypeError("Must be an integer")1587if i != 0 and i != 1:1588raise IndexError("The integer must be 0 or 1")15891590letters = map(self._alphabet.unrank, self._intervals[i])1591flips = self._flips[i]15921593return zip(letters,flips)15941595def __eq__(self,other):1596r"""1597Test of equality15981599ALGORITHM:16001601not considering the alphabet used for the representation but just the1602order16031604TESTS::16051606sage: p1 = iet.Permutation('a b c','c b a',flips='a')1607sage: p2 = iet.Permutation('a b c','c b a',flips='b')1608sage: p3 = iet.Permutation('d e f','f e d',flips='d')1609sage: p1 == p1 and p2 == p2 and p3 == p31610True1611sage: p1 == p21612False1613sage: p1 == p31614True1615"""1616return (1617type(self) == type(other) and1618self._intervals == other._intervals and1619self._flips == other._flips)16201621def __ne__(self,other):1622r"""1623Test of difference16241625ALGORITHM:16261627not considering the alphabet used for the representation16281629TESTS::16301631sage: p1 = iet.Permutation('a b c','c b a',flips='a')1632sage: p2 = iet.Permutation('a b c','c b a',flips='b')1633sage: p3 = iet.Permutation('d e f','f e d',flips='d')1634sage: p1 != p1 or p2 != p2 or p3 != p31635False1636sage: p1 != p21637True1638sage: p1 != p31639False1640"""1641return (1642type(self) != type(other) or1643self._intervals != other._intervals or1644self._flips != other._flips)16451646def _inversed(self):1647r"""1648Inversion of the permutation (called by tb_inverse).16491650.. TODO::16511652Resolve properly the mutability problem associated to hash1653value and twin list.16541655TESTS::16561657sage: p = iet.Permutation('a','a',flips='a')1658sage: p.tb_inverse() #indirect doctest1659-a1660-a1661sage: p = iet.Permutation('a b','a b',flips='a')1662sage: p.tb_inverse() #indirect doctest1663-a b1664-a b1665sage: p = iet.Permutation('a b','a b',flips='b')1666sage: p.tb_inverse() #indirect doctest1667a -b1668a -b1669sage: p = iet.Permutation('a b','b a',flips='a')1670sage: p.tb_inverse() #indirect doctest1671b -a1672-a b1673sage: p = iet.Permutation('a b','b a',flips='b')1674sage: p.tb_inverse() #indirect doctest1675-b a1676a -b1677"""1678if hasattr(self, '_twin'):1679delattr(self, '_twin')16801681if self._hash is not None:1682self._hash = None16831684self._intervals.reverse()1685self._flips.reverse()16861687def _reversed(self):1688r"""1689Reverses the permutation (called by lr_inverse)16901691.. TODO::16921693Resolve properly the mutability problem with _twin list1694and the hash value.16951696TESTS::16971698sage: p = iet.Permutation('a','a',flips='a')1699sage: p.lr_inverse() #indirect doctest1700-a1701-a1702sage: p = iet.Permutation('a b','a b',flips='a')1703sage: p.lr_inverse() #indirect doctest1704b -a1705b -a1706sage: p = iet.Permutation('a b','a b',flips='b')1707sage: p.lr_inverse() #indirect doctest1708-b a1709-b a1710sage: p = iet.Permutation('a b','b a',flips='a')1711sage: p.lr_inverse() #indirect doctest1712b -a1713-a b1714sage: p = iet.Permutation('a b','b a',flips='b')1715sage: p.lr_inverse() #indirect doctest1716-b a1717a -b1718"""1719if hasattr(self, '_twin'):1720delattr(self, '_twin')17211722if self._hash is not None:1723self._hash is None17241725self._intervals[0].reverse()1726self._intervals[1].reverse()1727self._flips[0].reverse()1728self._flips[1].reverse()17291730class FlippedLabelledPermutationIET(1731FlippedLabelledPermutation,1732FlippedPermutationIET,1733LabelledPermutationIET):1734r"""1735Flipped labelled permutation from iet.17361737EXAMPLES:17381739Reducibility testing (does not depends of flips)::17401741sage: p = iet.Permutation('a b c', 'c b a',flips='a')1742sage: p.is_irreducible()1743True1744sage: q = iet.Permutation('a b c d', 'b a d c', flips='bc')1745sage: q.is_irreducible()1746False17471748Rauzy movability and Rauzy move::17491750sage: p = iet.Permutation('a b c', 'c b a',flips='a')1751sage: print p1752-a b c1753c b -a1754sage: print p.rauzy_move(1)1755-c -a b1756-c b -a1757sage: print p.rauzy_move(0)1758-a b c1759c -a b17601761Rauzy diagrams::17621763sage: d = iet.RauzyDiagram('a b c d','d a b c',flips='a')17641765AUTHORS:17661767- Vincent Delecroix (2009-09-29): initial version1768"""1769def reduced(self):1770r"""1771The associated reduced permutation.17721773OUTPUT:17741775permutation -- the associated reduced permutation17761777EXAMPLES::17781779sage: p = iet.Permutation('a b c','c b a',flips='a')1780sage: q = iet.Permutation('a b c','c b a',flips='a',reduced=True)1781sage: p.reduced() == q1782True1783"""1784from sage.dynamics.interval_exchanges.reduced import FlippedReducedPermutationIET17851786return FlippedReducedPermutationIET(1787intervals=self.list(flips=False),1788flips=self.flips(),1789alphabet=self.alphabet())17901791def __hash__(self):1792r"""1793ALGORITHM:17941795Uses hash of string17961797TESTS::17981799sage: p =[]1800sage: p.append(iet.Permutation('a b','a b',flips='a'))1801sage: p.append(iet.Permutation('a b','a b',flips='b'))1802sage: p.append(iet.Permutation('a b','a b',flips='ab'))1803sage: p.append(iet.Permutation('a b','b a',flips='a'))1804sage: p.append(iet.Permutation('a b','b a',flips='b'))1805sage: p.append(iet.Permutation('a b','b a',flips='ab'))1806sage: h = map(hash, p)1807sage: for i in range(len(h)-1):1808....: if h[i] == h[i+1]:1809....: print "You choose a bad hash!"1810"""1811if self._hash is None:1812f = self._flips1813i = self._intervals1814l = []1815l.extend([str(j*(1+k)) for j,k in zip(f[0],i[0])])1816l.extend([str(-j*(1+k)) for j,k in zip(f[1],i[1])])1817self._hash = hash(''.join(l))18181819return self._hash18201821def rauzy_move(self,winner=None,side=None):1822r"""1823Returns the Rauzy move.18241825INPUT:18261827- ``winner`` - 'top' (or 't' or 0) or 'bottom' (or 'b' or 1)18281829- ``side`` - (default: 'right') 'right' (or 'r') or 'left' (or 'l')18301831OUTPUT:18321833permutation -- the Rauzy move of ``self``18341835EXAMPLES:18361837::18381839sage: p = iet.Permutation('a b','b a',flips='a')1840sage: p.rauzy_move('top')1841-a b1842b -a1843sage: p.rauzy_move('bottom')1844-b -a1845-b -a18461847::18481849sage: p = iet.Permutation('a b c','c b a',flips='b')1850sage: p.rauzy_move('top')1851a -b c1852c a -b1853sage: p.rauzy_move('bottom')1854a c -b1855c -b a1856"""1857winner = interval_conversion(winner)1858side = side_conversion(side)18591860result = copy(self)18611862winner_letter = result._intervals[winner][side]1863loser_letter = result._intervals[1-winner].pop(side)18641865winner_flip = result._flips[winner][side]1866loser_flip = result._flips[1-winner].pop(side)18671868loser_twin = result._intervals[winner].index(loser_letter)1869result._flips[winner][loser_twin] = winner_flip * loser_flip18701871loser_to = result._intervals[1-winner].index(winner_letter) - side1872if winner_flip == -1: loser_to += 1 + 2*side18731874result._intervals[1-winner].insert(loser_to, loser_letter)1875result._flips[1-winner].insert(loser_to, winner_flip * loser_flip)18761877return result18781879def rauzy_diagram(self, **kargs):1880r"""1881Returns the Rauzy diagram associated to this permutation.18821883For more information, try help(iet.RauzyDiagram)18841885OUTPUT:18861887RauzyDiagram -- the Rauzy diagram of ``self``18881889EXAMPLES::18901891sage: p = iet.Permutation('a b c', 'c b a',flips='a')1892sage: p.rauzy_diagram()1893Rauzy diagram with 3 permutations1894"""1895return FlippedLabelledRauzyDiagram(self, **kargs)18961897class FlippedLabelledPermutationLI(FlippedLabelledPermutation,1898FlippedPermutationLI,1899LabelledPermutationLI):1900r"""1901Flipped labelled quadratic (or generalized) permutation.19021903EXAMPLES:19041905Reducibility testing::19061907sage: p = iet.GeneralizedPermutation('a b b', 'c c a', flips='a')1908sage: p.is_irreducible()1909True19101911Reducibility testing with associated decomposition::19121913sage: p = iet.GeneralizedPermutation('a b c a', 'b d d c', flips='ab')1914sage: p.is_irreducible()1915False1916sage: test, decomp = p.is_irreducible(return_decomposition = True)1917sage: print test1918False1919sage: print decomp1920(['a'], ['c', 'a'], [], ['c'])19211922Rauzy movability and Rauzy move::19231924sage: p = iet.GeneralizedPermutation('a a b b c c', 'd d', flips='d')1925sage: p.has_rauzy_move(0)1926False1927sage: p.has_rauzy_move(1)1928True1929sage: p = iet.GeneralizedPermutation('a a b','b c c',flips='c')1930sage: p.has_rauzy_move(0)1931True1932sage: p.has_rauzy_move(1)1933True1934"""1935def reduced(self):1936r"""1937The associated reduced permutation.19381939OUTPUT:19401941permutation -- the associated reduced permutation19421943EXAMPLE::19441945sage: p = iet.GeneralizedPermutation('a a','b b c c',flips='a')1946sage: q = iet.GeneralizedPermutation('a a','b b c c',flips='a',reduced=True)1947sage: p.reduced() == q1948True1949"""1950from sage.dynamics.interval_exchanges.reduced import FlippedReducedPermutationLI19511952return FlippedReducedPermutationLI(1953intervals=self.list(flips=False),1954flips=self.flips(),1955alphabet=self.alphabet())19561957def right_rauzy_move(self, winner):1958r"""1959Perform a Rauzy move on the right (the standard one).19601961INPUT:19621963- ``winner`` - either 'top' or 'bottom' ('t' or 'b' for short)19641965OUTPUT:19661967permutation -- the Rauzy move of ``self``19681969EXAMPLES:19701971::19721973sage: p = iet.GeneralizedPermutation('a a b','b c c',flips='c')1974sage: p.right_rauzy_move(0)1975a a b1976-c b -c1977sage: p.right_rauzy_move(1)1978a a1979-b -c -b -c19801981::19821983sage: p = iet.GeneralizedPermutation('a b b','c c a',flips='ab')1984sage: p.right_rauzy_move(0)1985a -b a -b1986c c1987sage: p.right_rauzy_move(1)1988b -a b1989c c -a1990"""1991result = copy(self)19921993winner_letter = result._intervals[winner][-1]1994winner_flip = result._flips[winner][-1]19951996loser_letter = result._intervals[1-winner].pop(-1)1997loser_flip = result._flips[1-winner].pop(-1)19981999if loser_letter in result._intervals[winner]:2000loser_twin = result._intervals[winner].index(loser_letter)2001result._flips[winner][loser_twin] = loser_flip*winner_flip2002else:2003loser_twin = result._intervals[1-winner].index(loser_letter)2004result._flips[1-winner][loser_twin] = loser_flip*winner_flip20052006if winner_letter in result._intervals[winner][:-1]:2007loser_to = result._intervals[winner].index(winner_letter)2008if winner_flip == -1: loser_to += 12009result._intervals[winner].insert(loser_to, loser_letter)2010result._flips[winner].insert(loser_to, loser_flip*winner_flip)2011else:2012loser_to = result._intervals[1-winner].index(winner_letter)2013if loser_flip == 1: loser_to += 12014result._intervals[1-winner].insert(loser_to, loser_letter)2015result._flips[1-winner].insert(loser_to, loser_flip*winner_flip)20162017return result20182019def left_rauzy_move(self, winner):2020r"""2021Perform a Rauzy move on the left.20222023INPUT:20242025- ``winner`` - either 'top' or 'bottom' ('t' or 'b' for short)20262027OUTPUT:20282029-- a permutation20302031EXAMPLES:20322033::20342035sage: p = iet.GeneralizedPermutation('a a b','b c c')2036sage: p.left_rauzy_move(0)2037a a b b2038c c2039sage: p.left_rauzy_move(1)2040a a b2041b c c20422043::20442045sage: p = iet.GeneralizedPermutation('a b b','c c a')2046sage: p.left_rauzy_move(0)2047a b b2048c c a2049sage: p.left_rauzy_move(1)2050b b2051c c a a2052"""2053result = copy(self)20542055winner_letter = result._intervals[winner][0]2056loser_letter = result._intervals[1-winner].pop(0)20572058if winner_letter in result._intervals[winner][1:]:2059loser_to = result._intervals[winner][1:].index(winner_letter)+22060result._intervals[winner].insert(loser_to, loser_letter)20612062else:2063loser_to = result._intervals[1-winner].index(winner_letter)2064result._intervals[1-winner].insert(loser_to, loser_letter)20652066return result20672068def rauzy_diagram(self, **kargs):2069r"""2070Returns the associated Rauzy diagram.20712072For more information, try help(RauzyDiagram)20732074OUTPUT :20752076-- a RauzyDiagram20772078EXAMPLES::20792080sage: p = iet.GeneralizedPermutation('a b b a', 'c d c d')2081sage: d = p.rauzy_diagram()2082"""2083return FlippedLabelledRauzyDiagram(self, **kargs)20842085class LabelledRauzyDiagram(RauzyDiagram):2086r"""2087Template for Rauzy diagrams of labelled permutations.20882089.. WARNING::20902091DO NOT USE2092"""2093class Path(RauzyDiagram.Path):2094r"""2095Path in Labelled Rauzy diagram.2096"""2097def matrix(self):2098r"""2099Returns the matrix associated to a path.21002101The matrix associated to a Rauzy induction, is the linear2102application that allows to recover the lengths of ``self``2103from the lengths of the induced.21042105OUTPUT:21062107matrix -- a square matrix of integers21082109EXAMPLES:21102111::21122113sage: p = iet.Permutation('a1 a2','a2 a1')2114sage: d = p.rauzy_diagram()2115sage: g = d.path(p,'top')2116sage: g.matrix()2117[1 0]2118[1 1]2119sage: g = d.path(p,'bottom')2120sage: g.matrix()2121[1 1]2122[0 1]21232124::21252126sage: p = iet.Permutation('a b c','c b a')2127sage: d = p.rauzy_diagram()2128sage: g = d.path(p)2129sage: g.matrix() == identity_matrix(3)2130True2131sage: g = d.path(p,'top')2132sage: g.matrix()2133[1 0 0]2134[0 1 0]2135[1 0 1]2136sage: g = d.path(p,'bottom')2137sage: g.matrix()2138[1 0 1]2139[0 1 0]2140[0 0 1]2141"""2142return self.composition(self._parent.edge_to_matrix)21432144def interval_substitution(self):2145r"""2146Returns the substitution of intervals obtained.21472148OUTPUT:21492150WordMorphism -- the word morphism corresponding to the interval21512152EXAMPLES::21532154sage: p = iet.Permutation('a b','b a')2155sage: r = p.rauzy_diagram()2156sage: p0 = r.path(p,0)2157sage: s0 = p0.interval_substitution()2158sage: s02159WordMorphism: a->a, b->ba2160sage: p1 = r.path(p,1)2161sage: s1 = p1.interval_substitution()2162sage: s12163WordMorphism: a->ab, b->b2164sage: (p0 + p1).interval_substitution() == s1 * s02165True2166sage: (p1 + p0).interval_substitution() == s0 * s12167True2168"""2169return self.right_composition(self._parent.edge_to_interval_substitution)21702171def orbit_substitution(self):2172r"""2173Returns the substitution on the orbit of the left extremity.21742175OUTPUT:21762177WordMorhpism -- the word morphism corresponding to the orbit21782179EXAMPLES::21802181sage: p = iet.Permutation('a b','b a')2182sage: d = p.rauzy_diagram()2183sage: g0 = d.path(p,'top')2184sage: s0 = g0.orbit_substitution()2185sage: s02186WordMorphism: a->ab, b->b2187sage: g1 = d.path(p,'bottom')2188sage: s1 = g1.orbit_substitution()2189sage: s12190WordMorphism: a->a, b->ab2191sage: (g0 + g1).orbit_substitution() == s0 * s12192True2193sage: (g1 + g0).orbit_substitution() == s1 * s02194True2195"""2196return self.composition(self._parent.edge_to_orbit_substitution)21972198substitution = orbit_substitution # standard name2199dual_substitution = interval_substitution # standard name22002201def is_full(self):2202r"""2203Tests the fullness.22042205A path is full if all intervals win at least one time.22062207OUTPUT:22082209boolean -- ``True`` if the path is full and ``False`` else22102211EXAMPLE::22122213sage: p = iet.Permutation('a b c','c b a')2214sage: r = p.rauzy_diagram()2215sage: g0 = r.path(p,'t','b','t')2216sage: g1 = r.path(p,'b','t','b')2217sage: g0.is_full()2218False2219sage: g1.is_full()2220False2221sage: (g0 + g1).is_full()2222True2223sage: (g1 + g0).is_full()2224True2225"""2226return set(self._parent.letters()) == set(self.winners())22272228def edge_to_interval_substitution(self, p=None, edge_type=None):2229r"""2230Returns the interval substitution associated to an edge22312232OUTPUT:22332234WordMorphism -- the WordMorphism corresponding to the edge22352236EXAMPLE::22372238sage: p = iet.Permutation('a b c','c b a')2239sage: r = p.rauzy_diagram()2240sage: r.edge_to_interval_substitution(None,None)2241WordMorphism: a->a, b->b, c->c2242sage: r.edge_to_interval_substitution(p,0)2243WordMorphism: a->a, b->b, c->ca2244sage: r.edge_to_interval_substitution(p,1)2245WordMorphism: a->ac, b->b, c->c2246"""2247if p is None and edge_type is None:2248return WordMorphism(dict((a,a) for a in self.letters()))22492250function_name = self._edge_types[edge_type][0] + '_interval_substitution'2251if not hasattr(self._element_class,function_name):2252return WordMorphism(dict((a,a) for a in self.letters()))22532254arguments = self._edge_types[edge_type][1]22552256return getattr(p,function_name)(*arguments)22572258def edge_to_orbit_substitution(self, p=None, edge_type=None):2259r"""2260Returns the interval substitution associated to an edge22612262OUTPUT:22632264WordMorphism -- the word morphism corresponding to the edge22652266EXAMPLE::22672268sage: p = iet.Permutation('a b c','c b a')2269sage: r = p.rauzy_diagram()2270sage: r.edge_to_orbit_substitution(None,None)2271WordMorphism: a->a, b->b, c->c2272sage: r.edge_to_orbit_substitution(p,0)2273WordMorphism: a->ac, b->b, c->c2274sage: r.edge_to_orbit_substitution(p,1)2275WordMorphism: a->a, b->b, c->ac2276"""2277if p is None and edge_type is None:2278return WordMorphism(dict((a,a) for a in self.letters()))22792280function_name = self._edge_types[edge_type][0] + '_orbit_substitution'22812282if not hasattr(self._element_class,function_name):2283return WordMorphism(dict((a,a) for a in self.letters()))22842285arguments = self._edge_types[edge_type][1]2286return getattr(p,function_name)(*arguments)22872288def full_loop_iterator(self, start=None, max_length=1):2289r"""2290Returns an iterator over all full path starting at start.22912292INPUT:22932294- ``start`` - the start point22952296- ``max_length`` - a limit on the length of the paths22972298OUTPUT:22992300iterator -- iterator over full loops23012302EXAMPLE::23032304sage: p = iet.Permutation('a b','b a')2305sage: r = p.rauzy_diagram()2306sage: for g in r.full_loop_iterator(p,2):2307....: print g.matrix(), "\n*****"2308[1 1]2309[1 2]2310*****2311[2 1]2312[1 1]2313*****2314"""2315from itertools import ifilter, imap23162317g = self.path(start)23182319ifull = ifilter(2320lambda x: x.is_loop() and x.is_full(),2321self._all_path_extension(g,max_length))23222323return imap(copy,ifull)23242325def full_nloop_iterator(self, start=None, length=1):2326r"""2327Returns an iterator over all full loops of given length.23282329INPUT:23302331- ``start`` - the initial permutation23322333- ``length`` - the length to consider23342335OUTPUT:23362337iterator -- an iterator over the full loops of given length23382339EXAMPLE::23402341sage: p = iet.Permutation('a b','b a')2342sage: d = p.rauzy_diagram()2343sage: for g in d.full_nloop_iterator(p,2):2344....: print g.matrix(), "\n*****"2345[1 1]2346[1 2]2347*****2348[2 1]2349[1 1]2350*****2351"""2352from itertools import ifilter, imap23532354g = self.path(start)23552356ifull = ifilter(2357lambda x: x.is_loop() and x.is_full(),2358self._all_npath_extension(g,length))23592360return imap(copy, ifull)23612362def _permutation_to_vertex(self, p):2363r"""2364Translation of a labelled permutation to a vertex23652366INPUT:23672368- ``p`` - a labelled Permutation23692370TESTS::23712372sage: p = iet.Permutation('a b c','c b a')2373sage: r = p.rauzy_diagram()2374sage: p in r #indirect doctest2375True2376"""2377return (tuple(p._intervals[0]),tuple(p._intervals[1]))23782379def _set_element(self,data):2380r"""2381Sets self._element with data23822383TESTS::23842385sage: p = iet.Permutation('a b c','c b a')2386sage: r = p.rauzy_diagram()2387sage: r[p][0] == p.rauzy_move(0) #indirect doctest2388True2389sage: r[p][1] == p.rauzy_move(1) #indirect doctest2390True2391"""2392self._element._intervals = [list(data[0]), list(data[1])]23932394class FlippedLabelledRauzyDiagram(FlippedRauzyDiagram, LabelledRauzyDiagram):2395r"""2396Rauzy diagram of flipped labelled permutations2397"""2398def _permutation_to_vertex(self, p):2399r"""2400Returns what must be stored from p.24012402INPUT:24032404- ``p`` - a Flipped labelled permutation24052406TESTS::24072408sage: p = iet.Permutation('a b c','c b a',flips='a')2409sage: r = p.rauzy_diagram()2410sage: p in r #indirect doctest2411True2412"""2413return ((tuple(p._intervals[0]),tuple(p._intervals[1])),2414(tuple(p._flips[0]), tuple(p._flips[1])))24152416def _set_element(self, data):2417r"""2418Returns what the vertex i as a permutation.24192420TESTS::24212422sage: p = iet.Permutation('a b','b a',flips='a')2423sage: r = p.rauzy_diagram()2424sage: p in r #indirect doctest2425True2426"""2427self._element._intervals = [list(data[0][0]), list(data[0][1])]2428self._element._flips = [list(data[1][0]), list(data[1][1])]242924302431