| 1 | r""" |
| 2 | Factor-enumerable words |
| 3 | |
| 4 | Words having an algorithm that enumerates the factor of length n which |
| 5 | includes finite words and some family of infinite words. This file gathers |
| 6 | methods (e.g. ``rauzy_graph``) that depends only on the existence of such |
| 7 | an algorithm. |
| 8 | |
| 9 | AUTHORS: |
| 10 | |
| 11 | - Sebastien Labbe (February 24, 2010) : initial version |
| 12 | - Julien Leroy (March 2010): reduced_rauzy_graph |
| 13 | |
| 14 | EXAMPLES: |
| 15 | |
| 16 | Enumeration 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 | |
| 31 | The 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 | |
| 40 | Rauzy 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 | |
| 48 | Left-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 | #***************************************************************************** |
| 64 | from sage.misc.cachefunc import cached_method |
| 65 | from sage.combinat.words.abstract_word import Word_class |
| 66 | from itertools import product, chain, tee |
| 67 | from sage.sets.set import Set |
| 68 | from sage.rings.all import Infinity |
| 69 | |
| 70 | class 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 | |