Ticket #8604: trac_8604_nfactor_enumerable-sl.patch

File trac_8604_nfactor_enumerable-sl.patch, 34.3 KB (added by slabbe, 12 years ago)

Depends on #8429.

  • doc/en/reference/combinat/words.rst

    # HG changeset patch
    # User Sebastien Labbe <slabqc at gmail.com>
    # Date 1271183117 -7200
    # Node ID a0bf952ffed56cf0e57ba337eaa38cbfa808bbc1
    # Parent  a3f3f7bc75e6fbb6d2b05c1d0edbdd4654c55115
    #8604: Add the class Word_nfactor_enumerable and some methods
    
    diff --git a/doc/en/reference/combinat/words.rst b/doc/en/reference/combinat/words.rst
    a b Words 
    66
    77   ../sage/combinat/words/alphabet
    88   ../sage/combinat/words/abstract_word
     9   ../sage/combinat/words/nfactor_enumerable_word
    910   ../sage/combinat/words/finite_word
    1011   ../sage/combinat/words/infinite_word
    1112   ../sage/combinat/words/word
  • sage/combinat/words/finite_word.py

    diff --git a/sage/combinat/words/finite_word.py b/sage/combinat/words/finite_word.py
    a b As matrix and many other sage objects, w 
    146146#*****************************************************************************
    147147from itertools import islice, izip, cycle
    148148from sage.combinat.words.abstract_word import Word_class
     149from sage.combinat.words.nfactor_enumerable_word import Word_nfactor_enumerable
    149150from sage.combinat.words.words import Words
    150151from sage.misc.cachefunc import cached_method
    151152from sage.combinat.words.word_options import word_options
    152153from sage.rings.all import Integer, Infinity, ZZ
    153154
    154 class FiniteWord_class(Word_class):
     155class FiniteWord_class(Word_nfactor_enumerable):
    155156    def __str__(self):
    156157        r"""
    157158        Returns the full string representation of the word.
    exponent %s: the length of the word (%s) 
    10221023        """
    10231024        return self.suffix_tree().factor_iterator(n)
    10241025
    1025     def factor_set(self, n=None):
    1026         r"""
    1027         Returns the set of factors (of length n) of self.
    1028 
    1029         INPUT:
    1030 
    1031         - ``n`` - an integer or ``None`` (default: None).
    1032 
    1033         OUTPUT:
    1034 
    1035             If ``n`` is an integer, returns the set of all distinct
    1036             factors of length ``n``. If ``n`` is ``None``, returns the set
    1037             of all distinct factors.
    1038 
    1039         EXAMPLES::
    1040 
    1041             sage: w = Word('121')
    1042             sage: s = w.factor_set()
    1043             sage: sorted(s)
    1044             [word: , word: 1, word: 12, word: 121, word: 2, word: 21]
    1045 
    1046         ::
    1047 
    1048             sage: w = Word('1213121')
    1049             sage: for i in range(w.length()): sorted(w.factor_set(i))
    1050             [word: ]
    1051             [word: 1, word: 2, word: 3]
    1052             [word: 12, word: 13, word: 21, word: 31]
    1053             [word: 121, word: 131, word: 213, word: 312]
    1054             [word: 1213, word: 1312, word: 2131, word: 3121]
    1055             [word: 12131, word: 13121, word: 21312]
    1056             [word: 121312, word: 213121]
    1057 
    1058         ::
    1059 
    1060             sage: w = Word([1,2,1,2,3])
    1061             sage: s = w.factor_set()
    1062             sage: sorted(s)
    1063             [word: , word: 1, word: 12, word: 121, word: 1212, word: 12123, word: 123, word: 2, word: 21, word: 212, word: 2123, word: 23, word: 3]
    1064 
    1065         TESTS::
    1066            
    1067             sage: w = Word("xx")
    1068             sage: s = w.factor_set()
    1069             sage: sorted(s)
    1070             [word: , word: x, word: xx]
    1071 
    1072         ::
    1073 
    1074             sage: Set(Word().factor_set())
    1075             {word: }
    1076         """
    1077         from sage.sets.set import Set
    1078         return Set(set(self.factor_iterator(n)))
    1079 
    1080     def rauzy_graph(self, n):
    1081         r"""
    1082         Returns the Rauzy graph of the factors of length n of self.
    1083 
    1084         The vertices are the factors of length `n` and there is an edge from
    1085         `u` to `v` if `ua = bv` is a factor of length `n+1` for some letters
    1086         `a` and `b`. 
    1087 
    1088         INPUT:
    1089 
    1090         - ``n`` - integer
    1091 
    1092         EXAMPLES::
    1093 
    1094             sage: w = Word(range(10)); w
    1095             word: 0123456789
    1096             sage: g = w.rauzy_graph(3); g
    1097             Looped digraph on 8 vertices
    1098             sage: WordOptions(identifier='')
    1099             sage: g.vertices()
    1100             [012, 123, 234, 345, 456, 567, 678, 789]
    1101             sage: g.edges()
    1102             [(012, 123, 3),
    1103              (123, 234, 4),
    1104              (234, 345, 5),
    1105              (345, 456, 6),
    1106              (456, 567, 7),
    1107              (567, 678, 8),
    1108              (678, 789, 9)]
    1109             sage: WordOptions(identifier='word: ')
    1110 
    1111         ::
    1112 
    1113             sage: f = words.FibonacciWord()[:100]
    1114             sage: f.rauzy_graph(8)
    1115             Looped digraph on 9 vertices
    1116 
    1117         ::
    1118 
    1119             sage: w = Word('1111111')
    1120             sage: g = w.rauzy_graph(3)
    1121             sage: g.edges()
    1122             [(word: 111, word: 111, word: 1)]
    1123 
    1124         ::
    1125 
    1126             sage: w = Word('111')
    1127             sage: for i in range(5) : w.rauzy_graph(i)
    1128             Looped multi-digraph on 1 vertex
    1129             Looped digraph on 1 vertex
    1130             Looped digraph on 1 vertex
    1131             Looped digraph on 1 vertex
    1132             Looped digraph on 0 vertices
    1133 
    1134         Multi-edges are allowed for the empty word::
    1135 
    1136             sage: W = Words('abcde')
    1137             sage: w = W('abc')
    1138             sage: w.rauzy_graph(0)
    1139             Looped multi-digraph on 1 vertex
    1140             sage: _.edges()
    1141             [(word: , word: , word: a),
    1142              (word: , word: , word: b),
    1143              (word: , word: , word: c)]
    1144         """
    1145         from sage.graphs.digraph import DiGraph
    1146         multiedges = True if n == 0 else False
    1147         g = DiGraph(loops=True, multiedges=multiedges)
    1148         if n == self.length():
    1149             g.add_vertex(self)
    1150         else:
    1151             for w in self.factor_iterator(n+1):
    1152                 u = w[:-1]
    1153                 v = w[1:]
    1154                 a = w[-1:]
    1155                 g.add_edge(u,v,a)
    1156         return g
    1157 
    1158     def reduced_rauzy_graph(self, n):
    1159         r"""
    1160         Returns the reduced Rauzy graph of order `n` of self.
    1161 
    1162         INPUT:
    1163 
    1164         - ``n`` - non negative integer. Every vertex of a reduced
    1165           Rauzy graph of order `n` is a factor of length `n` of self.
    1166 
    1167         OUTPUT:
    1168 
    1169         Looped multi-digraph
    1170 
    1171         DEFINITION:
    1172 
    1173         For infinite periodic words (resp. for finite words of type `u^i
    1174         u[0:j]`), the reduced Rauzy graph of order `n` (resp. for `n`
    1175         smaller or equal to `(i-1)|u|+j`) is the directed graph whose
    1176         unique vertex is the prefix `p` of length `n` of self and which has
    1177         an only edge which is a loop on `p` labelled by `w[n+1:|w|] p`
    1178         where `w` is the unique return word to `p`.
    1179 
    1180         In other cases, it is the directed graph defined as followed.  Let
    1181         `G_n` be the Rauzy graph of order `n` of self. The vertices are the
    1182         vertices of `G_n` that are either special or not prolongable to the
    1183         right or to the left. For each couple (`u`, `v`) of such vertices
    1184         and each directed path in `G_n` from `u` to `v` that contains no
    1185         other vertices that are special, there is an edge from `u` to `v`
    1186         in the reduced Rauzy graph of order `n` whose label is the label of
    1187         the path in `G_n`.
    1188        
    1189         .. NOTE::
    1190 
    1191             In the case of infinite recurrent non periodic words, this
    1192             definition correspond to the following one that can be found in
    1193             [1] and [2]  where a simple path is a path that begins with a
    1194             special factor, ends with a special factor and contains no
    1195             other vertices that are special:
    1196 
    1197             The reduced Rauzy graph of factors of length `n` is obtained
    1198             from `G_n` by replacing each simple path `P=v_1 v_2 ...
    1199             v_{\ell}` with an edge `v_1 v_{\ell}` whose label is the
    1200             concatenation of the labels of the edges of `P`.
    1201 
    1202         EXAMPLES::
    1203 
    1204             sage: w = Word(range(10)); w
    1205             word: 0123456789
    1206             sage: g = w.reduced_rauzy_graph(3); g
    1207             Looped multi-digraph on 2 vertices
    1208             sage: g.vertices()
    1209             [word: 012, word: 789]
    1210             sage: g.edges()
    1211             [(word: 012, word: 789, word: 3456789)]
    1212 
    1213         For the Fibonacci word::
    1214 
    1215             sage: f = words.FibonacciWord()[:100]
    1216             sage: g = f.reduced_rauzy_graph(8);g
    1217             Looped multi-digraph on 2 vertices
    1218             sage: g.vertices()
    1219             [word: 01001010, word: 01010010]
    1220             sage: g.edges()
    1221             [(word: 01001010, word: 01010010, word: 010), (word: 01010010, word: 01001010, word: 01010), (word: 01010010, word: 01001010, word: 10)]
    1222 
    1223         For periodic words::
    1224 
    1225             sage: from itertools import cycle
    1226             sage: w = Word(cycle('abcd'))[:100]
    1227             sage: g = w.reduced_rauzy_graph(3)
    1228             sage: g.edges()
    1229             [(word: abc, word: abc, word: dabc)]
    1230 
    1231         ::
    1232 
    1233             sage: w = Word('111')
    1234             sage: for i in range(5) : w.reduced_rauzy_graph(i)
    1235             Looped digraph on 1 vertex
    1236             Looped digraph on 1 vertex
    1237             Looped digraph on 1 vertex
    1238             Looped multi-digraph on 1 vertex
    1239             Looped multi-digraph on 0 vertices
    1240 
    1241         For ultimately periodic words::
    1242 
    1243             sage: sigma = WordMorphism('a->abcd,b->cd,c->cd,d->cd')
    1244             sage: w = sigma.fixed_point('a')[:100]; w
    1245             word: abcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd...
    1246             sage: g = w.reduced_rauzy_graph(5)
    1247             sage: g.vertices()
    1248             [word: abcdc, word: cdcdc]
    1249             sage: g.edges()
    1250             [(word: abcdc, word: cdcdc, word: dc), (word: cdcdc, word: cdcdc, word: dc)]
    1251 
    1252         AUTHOR:
    1253 
    1254         Julien Leroy (March 2010): initial version
    1255 
    1256         REFERENCES:
    1257 
    1258         - [1] M. Bucci et al.  A. De Luca, A. Glen, L. Q. Zamboni, A
    1259           connection between palindromic and factor complexity using
    1260           return words," Advances in Applied Mathematics 42 (2009) 60-74.
    1261 
    1262         - [2] L'ubomira Balkova, Edita Pelantova, and Wolfgang Steiner.
    1263           Sequences with constant number of return words. Monatsh. Math,
    1264           155 (2008) 251-263.
    1265         """
    1266         from sage.graphs.all import DiGraph
    1267         from copy import copy
    1268         g = copy(self.rauzy_graph(n))     
    1269         # Otherwise it changes the rauzy_graph function.
    1270         l = [v for v in g if g.in_degree(v)==1 and g.out_degree(v)==1]
    1271         if g.num_verts() !=0 and len(l)==g.num_verts():       
    1272             # In this case, the Rauzy graph is simply a cycle.
    1273             g = DiGraph()
    1274             g.allow_loops(True)
    1275             g.add_vertex(self[:n])
    1276             g.add_edge(self[:n],self[:n],self[n:n+len(l)])
    1277         else:
    1278             g.allow_loops(True)
    1279             g.allow_multiple_edges(True)
    1280             for v in l:
    1281                 [i] = g.neighbors_in(v)
    1282                 [o] = g.neighbors_out(v)
    1283                 g.add_edge(i,o,g.edge_label(i,v)[0]*g.edge_label(v,o)[0])
    1284                 g.delete_vertex(v)
    1285         return g
    1286 
    12871026    def commutes_with(self, other):
    12881027        r"""
    12891028        Returns True if self commutes with other, and False otherwise.
  • new file sage/combinat/words/nfactor_enumerable_word.py

    diff --git a/sage/combinat/words/nfactor_enumerable_word.py b/sage/combinat/words/nfactor_enumerable_word.py
    new file mode 100644
    - +  
     1r"""
     2Factor-enumerable words
     3
     4Words having an algorithm that enumerates the factor of length n which
     5includes finite words and some family of infinite words. This file gathers
     6methods (e.g. ``rauzy_graph``) that depends only on the existence of such
     7an algorithm.
     8
     9AUTHORS:
     10
     11- Sebastien Labbe (February 24, 2010) : initial version
     12- Julien Leroy (March 2010): reduced_rauzy_graph
     13
     14EXAMPLES:
     15
     16Enumeration of factors::
     17
     18    sage: w = Word([4,5,6])^7
     19    sage: it = w.factor_iterator(4)
     20    sage: it.next()
     21    word: 6456
     22    sage: it.next()
     23    word: 5645
     24    sage: it.next()
     25    word: 4564
     26    sage: it.next()
     27    Traceback (most recent call last):
     28    ...
     29    StopIteration
     30
     31The set of factors::
     32
     33    sage: sorted(w.factor_set(3))
     34    [word: 456, word: 564, word: 645]
     35    sage: sorted(w.factor_set(4))
     36    [word: 4564, word: 5645, word: 6456]
     37    sage: w.factor_set().cardinality()
     38    61
     39
     40Rauzy graphs::
     41
     42    sage: f = words.FibonacciWord()[:30]
     43    sage: f.rauzy_graph(4)
     44    Looped digraph on 5 vertices
     45    sage: f.reduced_rauzy_graph(4)
     46    Looped multi-digraph on 2 vertices
     47
     48Left-special and bispecial factors::
     49
     50    sage: f.number_of_left_special_factors(7)
     51    1
     52    sage: f.bispecial_factors()
     53    [word: , word: 0, word: 010, word: 010010, word: 01001010010]
     54"""
     55#*****************************************************************************
     56#       Copyright (C) 2010 Sebastien Labbe <slabqc@gmail.com>,
     57#
     58#  Distributed under the terms of the GNU General Public License version 2 (GPLv2)
     59#
     60#  The full text of the GPLv2 is available at:
     61#
     62#                  http://www.gnu.org/licenses/
     63#*****************************************************************************
     64from sage.misc.cachefunc import cached_method
     65from sage.combinat.words.abstract_word import Word_class
     66from itertools import product, chain, tee
     67from sage.sets.set import Set
     68from sage.rings.all import Infinity
     69
     70class Word_nfactor_enumerable(Word_class):
     71    def factor_iterator(self, n=None):
     72        r"""
     73        Returns an iterator over the factor of lenght `n`.
     74
     75        INPUT:
     76
     77        -  ``n`` - an integer, or ``None``.
     78
     79        OUTPUT:
     80
     81            If ``n`` is an integer, returns an iterator over all distinct
     82            factors of length ``n``. If ``n`` is ``None``, returns an iterator
     83            generating all distinct factors.
     84
     85        .. NOTE:
     86
     87            This function must be implemented in a more specific class
     88            (e.g. finite word class).
     89
     90        EXAMPLES::
     91
     92            sage: w = Word(range(10))
     93            sage: sorted(w.factor_iterator(7))
     94            [word: 0123456, word: 1234567, word: 2345678, word: 3456789]
     95        """
     96        msg = 'This function must be defined in a inherited class'
     97        raise NotImplementedError, msg
     98
     99    def number_of_factors(self,n):
     100        r"""
     101        Return the number of distinct factors of self.
     102
     103        INPUT:
     104
     105        -  ``n`` - an integer
     106
     107        OUTPUT:
     108
     109            integer
     110
     111        EXAMPLES::
     112
     113            sage: w = Word(range(10))
     114            sage: w.number_of_factors(6)
     115            5
     116        """
     117        return len(list(self.factor_iterator(n)))
     118
     119    def factor_set(self, n=None):
     120        r"""
     121        Returns the set of factors (of length n) of self.
     122
     123        INPUT:
     124
     125        - ``n`` - an integer or ``None`` (default: None).
     126
     127        OUTPUT:
     128
     129            If ``n`` is an integer, returns the set of all distinct
     130            factors of length ``n``. If ``n`` is ``None``, returns the set
     131            of all distinct factors.
     132
     133        EXAMPLES::
     134
     135            sage: w = Word('121')
     136            sage: s = w.factor_set()
     137            sage: sorted(s)
     138            [word: , word: 1, word: 12, word: 121, word: 2, word: 21]
     139
     140        ::
     141
     142            sage: w = Word('1213121')
     143            sage: for i in range(w.length()): sorted(w.factor_set(i))
     144            [word: ]
     145            [word: 1, word: 2, word: 3]
     146            [word: 12, word: 13, word: 21, word: 31]
     147            [word: 121, word: 131, word: 213, word: 312]
     148            [word: 1213, word: 1312, word: 2131, word: 3121]
     149            [word: 12131, word: 13121, word: 21312]
     150            [word: 121312, word: 213121]
     151
     152        ::
     153
     154            sage: w = Word([1,2,1,2,3])
     155            sage: s = w.factor_set()
     156            sage: sorted(s)
     157            [word: , word: 1, word: 12, word: 121, word: 1212, word: 12123, word: 123, word: 2, word: 21, word: 212, word: 2123, word: 23, word: 3]
     158
     159        TESTS::
     160           
     161            sage: w = Word("xx")
     162            sage: s = w.factor_set()
     163            sage: sorted(s)
     164            [word: , word: x, word: xx]
     165
     166        ::
     167
     168            sage: Set(Word().factor_set())
     169            {word: }
     170        """
     171        return Set(set(self.factor_iterator(n)))
     172
     173    def topological_entropy(self, n):
     174        r"""
     175        Return the topological entropy for the factors of length n.
     176
     177        The topological entropy of a sequence `u` is defined as the
     178        exponential growth rate of the complexity of `u` as the length
     179        increases: `H_{top}(u)=\lim_{n\to\infty}\frac{\log_d(p_u(n))}{n}`
     180        where `d` denotes the cardinality of the alphabet and `p_u(n)` is
     181        the complexity function, i.e. the number of factors of length `n`
     182        in the sequence `u` [1].
     183
     184        INPUT:
     185
     186        - ``self`` - a word defined over a finite alphabet
     187        -  ``n`` - positive integer
     188
     189        OUTPUT:
     190
     191        real number (a symbolic expression)
     192
     193        EXAMPLES::
     194
     195            sage: W = Words([0, 1])
     196            sage: w = W([0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1])
     197            sage: t = w.topological_entropy(3); t
     198            1/3*log(7)/log(2)
     199            sage: n(t)
     200            0.935784974019201
     201
     202        ::
     203
     204            sage: w = words.ThueMorseWord()[:100]
     205            sage: topo = w.topological_entropy
     206            sage: for i in range(0, 41, 5): print i, n(topo(i), digits=5)
     207            0 1.0000
     208            5 0.71699
     209            10 0.48074
     210            15 0.36396
     211            20 0.28774
     212            25 0.23628
     213            30 0.20075
     214            35 0.17270
     215            40 0.14827
     216
     217        If no alphabet is specified, an error is raised::
     218
     219            sage: w = Word(range(20))
     220            sage: w.topological_entropy(3)
     221            Traceback (most recent call last):
     222            ...
     223            TypeError: The word must be defined over a finite alphabet
     224
     225        The following is ok::
     226
     227            sage: W = Words(range(20))
     228            sage: w = W(range(20))
     229            sage: w.topological_entropy(3)
     230            1/3*log(18)/log(20)
     231
     232        REFERENCES:
     233
     234           [1] N. Pytheas Fogg, Substitutions in Dynamics, Arithmetics,
     235           and Combinatorics, Lecture Notes in Mathematics 1794, Springer
     236           Verlag. V. Berthe, S. Ferenczi, C. Mauduit and A. Siegel, Eds.
     237           (2002).   
     238        """
     239        d = self.parent().size_of_alphabet()
     240        if d is Infinity:
     241            raise TypeError, "The word must be defined over a finite alphabet"
     242        if n == 0:
     243            return 1
     244        pn = self.number_of_factors(n)
     245        from sage.functions.all import log
     246        return log(pn, base=d)/n
     247
     248    @cached_method
     249    def rauzy_graph(self, n):
     250        r"""
     251        Returns the Rauzy graph of the factors of length n of self.
     252
     253        The vertices are the factors of length `n` and there is an edge from
     254        `u` to `v` if `ua = bv` is a factor of length `n+1` for some letters
     255        `a` and `b`. 
     256
     257        INPUT:
     258
     259        - ``n`` - integer
     260
     261        EXAMPLES::
     262
     263            sage: w = Word(range(10)); w
     264            word: 0123456789
     265            sage: g = w.rauzy_graph(3); g
     266            Looped digraph on 8 vertices
     267            sage: WordOptions(identifier='')
     268            sage: g.vertices()
     269            [012, 123, 234, 345, 456, 567, 678, 789]
     270            sage: g.edges()
     271            [(012, 123, 3),
     272             (123, 234, 4),
     273             (234, 345, 5),
     274             (345, 456, 6),
     275             (456, 567, 7),
     276             (567, 678, 8),
     277             (678, 789, 9)]
     278            sage: WordOptions(identifier='word: ')
     279
     280        ::
     281
     282            sage: f = words.FibonacciWord()[:100]
     283            sage: f.rauzy_graph(8)
     284            Looped digraph on 9 vertices
     285
     286        ::
     287
     288            sage: w = Word('1111111')
     289            sage: g = w.rauzy_graph(3)
     290            sage: g.edges()
     291            [(word: 111, word: 111, word: 1)]
     292
     293        ::
     294
     295            sage: w = Word('111')
     296            sage: for i in range(5) : w.rauzy_graph(i)
     297            Looped multi-digraph on 1 vertex
     298            Looped digraph on 1 vertex
     299            Looped digraph on 1 vertex
     300            Looped digraph on 1 vertex
     301            Looped digraph on 0 vertices
     302
     303        Multi-edges are allowed for the empty word::
     304
     305            sage: W = Words('abcde')
     306            sage: w = W('abc')
     307            sage: w.rauzy_graph(0)
     308            Looped multi-digraph on 1 vertex
     309            sage: _.edges()
     310            [(word: , word: , word: a),
     311             (word: , word: , word: b),
     312             (word: , word: , word: c)]
     313        """
     314        from sage.graphs.digraph import DiGraph
     315        multiedges = True if n == 0 else False
     316        g = DiGraph(loops=True, multiedges=multiedges)
     317        if n == self.length():
     318            g.add_vertex(self)
     319        else:
     320            for w in self.factor_iterator(n+1):
     321                u = w[:-1]
     322                v = w[1:]
     323                a = w[-1:]
     324                g.add_edge(u,v,a)
     325        return g
     326
     327    def reduced_rauzy_graph(self, n):
     328        r"""
     329        Returns the reduced Rauzy graph of order `n` of self.
     330
     331        INPUT:
     332
     333        - ``n`` - non negative integer. Every vertex of a reduced
     334          Rauzy graph of order `n` is a factor of length `n` of self.
     335
     336        OUTPUT:
     337
     338        Looped multi-digraph
     339
     340        DEFINITION:
     341
     342        For infinite periodic words (resp. for finite words of type `u^i
     343        u[0:j]`), the reduced Rauzy graph of order `n` (resp. for `n`
     344        smaller or equal to `(i-1)|u|+j`) is the directed graph whose
     345        unique vertex is the prefix `p` of length `n` of self and which has
     346        an only edge which is a loop on `p` labelled by `w[n+1:|w|] p`
     347        where `w` is the unique return word to `p`.
     348
     349        In other cases, it is the directed graph defined as followed.  Let
     350        `G_n` be the Rauzy graph of order `n` of self. The vertices are the
     351        vertices of `G_n` that are either special or not prolongable to the
     352        right or to the left. For each couple (`u`, `v`) of such vertices
     353        and each directed path in `G_n` from `u` to `v` that contains no
     354        other vertices that are special, there is an edge from `u` to `v`
     355        in the reduced Rauzy graph of order `n` whose label is the label of
     356        the path in `G_n`.
     357       
     358        .. NOTE::
     359
     360            In the case of infinite recurrent non periodic words, this
     361            definition correspond to the following one that can be found in
     362            [1] and [2]  where a simple path is a path that begins with a
     363            special factor, ends with a special factor and contains no
     364            other vertices that are special:
     365
     366            The reduced Rauzy graph of factors of length `n` is obtained
     367            from `G_n` by replacing each simple path `P=v_1 v_2 ...
     368            v_{\ell}` with an edge `v_1 v_{\ell}` whose label is the
     369            concatenation of the labels of the edges of `P`.
     370
     371        EXAMPLES::
     372
     373            sage: w = Word(range(10)); w
     374            word: 0123456789
     375            sage: g = w.reduced_rauzy_graph(3); g
     376            Looped multi-digraph on 2 vertices
     377            sage: g.vertices()
     378            [word: 012, word: 789]
     379            sage: g.edges()
     380            [(word: 012, word: 789, word: 3456789)]
     381
     382        For the Fibonacci word::
     383
     384            sage: f = words.FibonacciWord()[:100]
     385            sage: g = f.reduced_rauzy_graph(8);g
     386            Looped multi-digraph on 2 vertices
     387            sage: g.vertices()
     388            [word: 01001010, word: 01010010]
     389            sage: g.edges()
     390            [(word: 01001010, word: 01010010, word: 010), (word: 01010010, word: 01001010, word: 01010), (word: 01010010, word: 01001010, word: 10)]
     391
     392        For periodic words::
     393
     394            sage: from itertools import cycle
     395            sage: w = Word(cycle('abcd'))[:100]
     396            sage: g = w.reduced_rauzy_graph(3)
     397            sage: g.edges()
     398            [(word: abc, word: abc, word: dabc)]
     399
     400        ::
     401
     402            sage: w = Word('111')
     403            sage: for i in range(5) : w.reduced_rauzy_graph(i)
     404            Looped digraph on 1 vertex
     405            Looped digraph on 1 vertex
     406            Looped digraph on 1 vertex
     407            Looped multi-digraph on 1 vertex
     408            Looped multi-digraph on 0 vertices
     409
     410        For ultimately periodic words::
     411
     412            sage: sigma = WordMorphism('a->abcd,b->cd,c->cd,d->cd')
     413            sage: w = sigma.fixed_point('a')[:100]; w
     414            word: abcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd...
     415            sage: g = w.reduced_rauzy_graph(5)
     416            sage: g.vertices()
     417            [word: abcdc, word: cdcdc]
     418            sage: g.edges()
     419            [(word: abcdc, word: cdcdc, word: dc), (word: cdcdc, word: cdcdc, word: dc)]
     420
     421        AUTHOR:
     422
     423        Julien Leroy (March 2010): initial version
     424
     425        REFERENCES:
     426
     427        - [1] M. Bucci et al.  A. De Luca, A. Glen, L. Q. Zamboni, A
     428          connection between palindromic and factor complexity using
     429          return words," Advances in Applied Mathematics 42 (2009) 60-74.
     430
     431        - [2] L'ubomira Balkova, Edita Pelantova, and Wolfgang Steiner.
     432          Sequences with constant number of return words. Monatsh. Math,
     433          155 (2008) 251-263.
     434        """
     435        from sage.graphs.all import DiGraph
     436        from copy import copy
     437        g = copy(self.rauzy_graph(n))     
     438        # Otherwise it changes the rauzy_graph function.
     439        l = [v for v in g if g.in_degree(v)==1 and g.out_degree(v)==1]
     440        if g.num_verts() !=0 and len(l)==g.num_verts():       
     441            # In this case, the Rauzy graph is simply a cycle.
     442            g = DiGraph()
     443            g.allow_loops(True)
     444            g.add_vertex(self[:n])
     445            g.add_edge(self[:n],self[:n],self[n:n+len(l)])
     446        else:
     447            g.allow_loops(True)
     448            g.allow_multiple_edges(True)
     449            for v in l:
     450                [i] = g.neighbors_in(v)
     451                [o] = g.neighbors_out(v)
     452                g.add_edge(i,o,g.edge_label(i,v)[0]*g.edge_label(v,o)[0])
     453                g.delete_vertex(v)
     454        return g
     455
     456    def _left_special_factors_iterator(self, n=None):
     457        r"""
     458        Returns an iterator over the left special factors (of length n).
     459
     460        A factor `u` of a word `w` is *left special* if there are
     461        two distinct letters `a` and `b` such that `au` and `bu`
     462        are factors of `w`.
     463
     464        INPUT:
     465
     466        -  ``n`` - integer (optional, default: None). If None, it returns
     467           an iterator over all left special factors.
     468
     469        EXAMPLES:
     470
     471            sage: alpha, beta, x = 0.54, 0.294, 0.1415
     472            sage: w = words.CodingOfRotationWord(alpha, beta, x)[:40]
     473            sage: sorted(w._left_special_factors_iterator(3))
     474            [word: 000, word: 010]
     475            sage: sorted(w._left_special_factors_iterator(4))
     476            [word: 0000, word: 0101]
     477            sage: sorted(w._left_special_factors_iterator(5))
     478            [word: 00000, word: 01010]
     479        """
     480        if n is None:
     481            for i in range(self.length()):
     482                for w in self._left_special_factors_iterator(i):
     483                    yield w
     484        else:
     485            g = self.rauzy_graph(n)
     486            in_d = g.in_degree
     487            for v in g:
     488                if in_d(v) > 1:
     489                    yield v
     490
     491    def left_special_factors(self, n=None):
     492        r"""
     493        Returns the left special factors (of length n).
     494
     495        A factor `u` of a word `w` is *left special* if there are
     496        two distinct letters `a` and `b` such that `au` and `bu`
     497        are factors of `w`.
     498
     499        INPUT:
     500
     501        -  ``n`` - integer (optional, default: None). If None, it returns
     502           all left special factors.
     503
     504        OUTPUT:
     505
     506        A list of words.
     507
     508        EXAMPLES::
     509
     510            sage: alpha, beta, x = 0.54, 0.294, 0.1415
     511            sage: w = words.CodingOfRotationWord(alpha, beta, x)[:40]
     512            sage: for i in range(5): print i, sorted(w.right_special_factors(i))
     513            0 [word: ]
     514            1 [word: 0]
     515            2 [word: 00, word: 10]
     516            3 [word: 000, word: 010]
     517            4 [word: 0000, word: 1010]
     518        """
     519        return list(self._left_special_factors_iterator(n))
     520
     521    def _right_special_factors_iterator(self, n=None):
     522        r"""
     523        Returns an iterator over the right special factors (of length n).
     524
     525        A factor `u` of a word `w` is *right special* if there are
     526        two distinct letters `a` and `b` such that `ua` and `ub`
     527        are factors of `w`.
     528
     529        INPUT:
     530
     531        -  ``n`` - integer (optional, default: None). If None, it returns
     532           an iterator over all right special factors.
     533
     534        EXAMPLES:
     535
     536            sage: alpha, beta, x = 0.61, 0.54, 0.3
     537            sage: w = words.CodingOfRotationWord(alpha, beta, x)[:40]
     538            sage: sorted(w._right_special_factors_iterator(3))
     539            [word: 010, word: 101]
     540            sage: sorted(w._right_special_factors_iterator(4))
     541            [word: 0101, word: 1010]
     542            sage: sorted(w._right_special_factors_iterator(5))
     543            [word: 00101, word: 11010]
     544        """
     545        if n is None:
     546            for i in range(self.length()):
     547                for w in self._right_special_factors_iterator(i):
     548                    yield w
     549        else:
     550            g = self.rauzy_graph(n)
     551            out_d = g.out_degree
     552            for v in g:
     553                if out_d(v) > 1:
     554                    yield v
     555
     556    def right_special_factors(self, n=None):
     557        r"""
     558        Returns the right special factors (of length n).
     559
     560        A factor `u` of a word `w` is *right special* if there are
     561        two distinct letters `a` and `b` such that `ua` and `ub`
     562        are factors of `w`.
     563
     564        INPUT:
     565
     566        -  ``n`` - integer (optional, default: None). If None, it returns
     567           all right special factors.
     568
     569        OUTPUT:
     570
     571        A list of words.
     572
     573        EXAMPLES::
     574
     575            sage: w = words.ThueMorseWord()[:30]
     576            sage: for i in range(5): print i, sorted(w.right_special_factors(i))
     577            0 [word: ]
     578            1 [word: 0, word: 1]
     579            2 [word: 01, word: 10]
     580            3 [word: 001, word: 010, word: 101, word: 110]
     581            4 [word: 0110, word: 1001]
     582        """
     583        return list(self._right_special_factors_iterator(n))
     584
     585    def _bispecial_factors_iterator(self, n=None):
     586        r"""
     587        Returns an iterator over the bispecial factors (of length n).
     588
     589        A factor `u` of a word `w` is *bispecial* if it is right special
     590        and left special.
     591
     592        INPUT:
     593
     594        -  ``n`` - integer (optional, default: None). If None, it returns
     595           an iterator over all bispecial factors.
     596
     597        EXAMPLES:
     598           
     599            sage: w = words.ThueMorseWord()[:30]
     600            sage: for i in range(10):
     601            ...     for u in w._bispecial_factors_iterator(i):
     602            ...         print i,u
     603            0 word:
     604            1 word: 1
     605            1 word: 0
     606            2 word: 10
     607            2 word: 01
     608            3 word: 101
     609            3 word: 010
     610            4 word: 0110
     611            4 word: 1001
     612            6 word: 100110
     613            6 word: 011001
     614            8 word: 10010110
     615
     616        ::
     617
     618            sage: for u in w._bispecial_factors_iterator(): u
     619            word:
     620            word: 1
     621            word: 0
     622            word: 10
     623            word: 01
     624            word: 101
     625            word: 010
     626            word: 0110
     627            word: 1001
     628            word: 100110
     629            word: 011001
     630            word: 10010110
     631        """
     632        if n is None:
     633            for i in range(self.length()):
     634                for w in self._bispecial_factors_iterator(i):
     635                    yield w
     636        else:
     637            g = self.rauzy_graph(n)
     638            in_d = g.in_degree
     639            out_d = g.out_degree
     640            for v in g:
     641                if out_d(v) > 1 and in_d(v) > 1:
     642                    yield v
     643
     644    def bispecial_factors(self, n=None):
     645        r"""
     646        Returns the bispecial factors (of length n).
     647
     648        A factor `u` of a word `w` is *bispecial* if it is right special
     649        and left special.
     650
     651        INPUT:
     652
     653        -  ``n`` - integer (optional, default: None). If None, it returns
     654           all bispecial factors.
     655
     656        OUTPUT:
     657
     658        A list of words.
     659
     660        EXAMPLES::
     661           
     662            sage: w = words.FibonacciWord()[:30]
     663            sage: w.bispecial_factors()
     664            [word: , word: 0, word: 010, word: 010010, word: 01001010010]
     665
     666        ::
     667
     668            sage: w = words.ThueMorseWord()[:30]
     669            sage: for i in range(10): print i, sorted(w.bispecial_factors(i))
     670            0 [word: ]
     671            1 [word: 0, word: 1]
     672            2 [word: 01, word: 10]
     673            3 [word: 010, word: 101]
     674            4 [word: 0110, word: 1001]
     675            5 []
     676            6 [word: 011001, word: 100110]
     677            7 []
     678            8 [word: 10010110]
     679            9 []
     680        """
     681        return list(self._bispecial_factors_iterator(n))
     682
     683    def number_of_left_special_factors(self, n):
     684        r"""
     685        Returns the number of left special factors of length n.
     686
     687        A factor `u` of a word `w` is *left special* if there are
     688        two distinct letters `a` and `b` such that `au` and `bu`
     689        are factors of `w`.
     690
     691        INPUT:
     692
     693        -  ``n`` - integer
     694
     695        OUTPUT:
     696
     697        Non negative integer
     698
     699        EXAMPLES::
     700
     701            sage: w = words.FibonacciWord()[:100]
     702            sage: [w.number_of_left_special_factors(i) for i in range(10)]
     703            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
     704
     705        ::
     706
     707            sage: w = words.ThueMorseWord()[:100]
     708            sage: [w.number_of_left_special_factors(i) for i in range(10)]
     709            [1, 2, 2, 4, 2, 4, 4, 2, 2, 4]
     710        """
     711        L = self.rauzy_graph(n).in_degree()
     712        return sum(1 for i in L if i>1)
     713
     714    def number_of_right_special_factors(self, n):
     715        r"""
     716        Returns the number of right special factors of length n.
     717
     718        A factor `u` of a word `w` is *right special* if there are
     719        two distinct letters `a` and `b` such that `ua` and `ub`
     720        are factors of `w`.
     721
     722        INPUT:
     723
     724        -  ``n`` - integer
     725
     726        OUTPUT:
     727
     728        Non negative integer
     729
     730        EXAMPLES::
     731
     732            sage: w = words.FibonacciWord()[:100]
     733            sage: [w.number_of_right_special_factors(i) for i in range(10)]
     734            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
     735
     736        ::
     737
     738            sage: w = words.ThueMorseWord()[:100]
     739            sage: [w.number_of_right_special_factors(i) for i in range(10)]
     740            [1, 2, 2, 4, 2, 4, 4, 2, 2, 4]
     741        """
     742        L = self.rauzy_graph(n).out_degree()
     743        return sum(1 for i in L if i>1)
     744