# HG changeset patch
# User Franco Saliola <saliola@gmail.com>
# Date 1247865952 -7200
# Node ID 77b673b9aca332cb2686855a79f0846e28c0bca4
# Parent  ca1f31d6f6bf7b1f8da0cb8973c838ab19921c29
trac #6519: Improve the words library code

diff -r ca1f31d6f6bf -r 77b673b9aca3 module_list.py
--- a/module_list.py	Thu Jul 09 15:14:36 2009 -0700
+++ b/module_list.py	Fri Jul 17 23:25:52 2009 +0200
@@ -164,6 +164,12 @@
               depends = ['sage/combinat/partitions_c.h'],
               language='c++'),
 
+    Extension('sage.combinat.words.word_datatypes',
+            sources=['sage/combinat/words/word_datatypes.pyx'],
+            include_dirs = ['sage/combinat/words'],
+            libraries = ['stdc++'],
+            language='c++'),
+            
     ################################
     ## 
     ## sage.ext
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/all.py
--- a/sage/combinat/all.py	Thu Jul 09 15:14:36 2009 -0700
+++ b/sage/combinat/all.py	Fri Jul 17 23:25:52 2009 +0200
@@ -51,8 +51,6 @@
 from ribbon_tableau import RibbonTableaux, RibbonTableau, MultiSkewTableau, SemistandardMultiSkewTableaux
 
 #Words
-#from word import Words, ShuffleProduct
-# sage-words replaces Words
 from words.all import *
 
 from subword import Subwords
@@ -72,7 +70,7 @@
 from set_partition_ordered import OrderedSetPartitions
 from subset import Subsets
 from necklace import Necklaces
-from lyndon_word import LyndonWords, StandardBracketedLyndonWords
+from lyndon_word import LyndonWord, LyndonWords, StandardBracketedLyndonWords
 from dyck_word import DyckWords, DyckWord
 from sloane_functions import sloane
 
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/lyndon_word.py
--- a/sage/combinat/lyndon_word.py	Thu Jul 09 15:14:36 2009 -0700
+++ b/sage/combinat/lyndon_word.py	Fri Jul 17 23:25:52 2009 +0200
@@ -23,9 +23,13 @@
 import __builtin__
 import necklace
 from integer_vector import IntegerVectors
-from sage.combinat.words.word import Word
 
-def LyndonWords(e, k=None):
+from sage.combinat.words.word import FiniteWord_list, FiniteWord_class
+from sage.combinat.words.words import Words_all, FiniteWords_length_k_over_OrderedAlphabet
+from sage.rings.integer_ring import ZZ
+from sage.combinat.words.alphabet import OrderedAlphabet
+
+def LyndonWords(e=None, k=None):
     """
     Returns the combinatorial class of Lyndon words.
     
@@ -37,11 +41,11 @@
         sage: LW = LyndonWords(3,3); LW
         Lyndon words from an alphabet of size 3 of length 3
         sage: LW.first()
-        [1, 1, 2]
+        word: 112
         sage: LW.last()
-        [2, 3, 3]
+        word: 233
         sage: LW.random_element()
-        [1, 1, 2]
+        word: 112
         sage: LW.cardinality()
         8
     
@@ -51,13 +55,15 @@
     ::
     
         sage: LyndonWords([2, 0, 1]).list()
-        [[1, 1, 3]]
+        [word: 113]
         sage: LyndonWords([2, 0, 1, 0, 1]).list()
-        [[1, 1, 3, 5], [1, 1, 5, 3], [1, 3, 1, 5]]
+        [word: 1135, word: 1153, word: 1315]
         sage: LyndonWords([2, 1, 1]).list()
-        [[1, 1, 2, 3], [1, 1, 3, 2], [1, 2, 1, 3]]
+        [word: 1123, word: 1132, word: 1213]
     """
-    if isinstance(e, (int, Integer)):
+    if e is None and k is None:
+        return LyndonWords_class()
+    elif isinstance(e, (int, Integer)):
         if e > 0:
             if not isinstance(k, (int, Integer)):
                 raise TypeError, "k must be a non-negative integer"
@@ -69,6 +75,29 @@
     
     raise TypeError, "e must be a positive integer or a composition"
 
+class LyndonWord(FiniteWord_list):
+    def __init__(self, data, check=True):
+        super(LyndonWord,self).__init__(parent=LyndonWords(),data=data)
+        if check and not self.is_lyndon():
+            raise ValueError, "Not a Lyndon word"
+
+class LyndonWords_class(Words_all):
+    def __repr__(self):
+        return "Lyndon words"
+
+    def __contains__(self, x):
+        """
+        TESTS::
+        
+            sage: LW33 = LyndonWords(3,3)
+            sage: all([lw in LyndonWords() for lw in LW33])
+            True
+        """
+        try:
+            return LyndonWord(x)
+        except ValueError:
+            return False
+
 class LyndonWords_evaluation(CombinatorialClass):
     def __init__(self, e):
         """
@@ -101,18 +130,14 @@
             sage: all([ lw in LyndonWords([2,1,3,1]) for lw in LyndonWords([2,1,3,1])])
             True
         """
-        if x not in necklace.Necklaces(self.e):
+        try:
+            w = LyndonWord(x)
+        except ValueError:
             return False
-        
-        #Check to make sure that x is aperiodic
-        xl = list(x)
-        n = sum(self.e)
-        cyclic_shift = xl[:]
-        for i in range(n - 1):
-            cyclic_shift = cyclic_shift[1:] + cyclic_shift[:1]
-            if cyclic_shift == xl:
+        ed = w.evaluation_dict()
+        for (i,a) in enumerate(self.e):
+            if ed[i+1] != a:
                 return False
-
         return True
 
     def cardinality(self):
@@ -147,7 +172,6 @@
 
         return sum([moebius(j)*factorial(n/j) / prod([factorial(ni/j) for ni in evaluation]) for j in divisors(gcd(le))])/n
 
-
     def __iter__(self):
         """
         An iterator for the Lyndon words with evaluation e.
@@ -155,35 +179,29 @@
         EXAMPLES::
         
             sage: LyndonWords([1]).list()    #indirect doctest
-            [[1]]
+            [word: 1]
             sage: LyndonWords([2]).list()    #indirect doctest
             []
             sage: LyndonWords([3]).list()    #indirect doctest
             []
             sage: LyndonWords([3,1]).list()  #indirect doctest
-            [[1, 1, 1, 2]]
+            [word: 1112]
             sage: LyndonWords([2,2]).list()  #indirect doctest
-            [[1, 1, 2, 2]]
+            [word: 1122]
             sage: LyndonWords([1,3]).list()  #indirect doctest
-            [[1, 2, 2, 2]]
+            [word: 1222]
             sage: LyndonWords([3,3]).list()  #indirect doctest
-            [[1, 1, 1, 2, 2, 2], [1, 1, 2, 1, 2, 2], [1, 1, 2, 2, 1, 2]]
+            [word: 111222, word: 112122, word: 112212]
             sage: LyndonWords([4,3]).list()  #indirect doctest
-            [[1, 1, 1, 1, 2, 2, 2],
-             [1, 1, 1, 2, 1, 2, 2],
-             [1, 1, 1, 2, 2, 1, 2],
-             [1, 1, 2, 1, 1, 2, 2],
-             [1, 1, 2, 1, 2, 1, 2]]
+            [word: 1111222, word: 1112122, word: 1112212, word: 1121122, word: 1121212]
         """
         if self.e == []:
             return
 
         for z in necklace._sfc(self.e, equality=True):
-            yield [i+1 for i in z]
+            yield LyndonWord([i+1 for i in z], check=False)
 
-
-
-class LyndonWords_nk(CombinatorialClass):
+class LyndonWords_nk(FiniteWords_length_k_over_OrderedAlphabet):
     def __init__(self, n, k):
         """
         TESTS::
@@ -195,6 +213,8 @@
         """
         self.n = Integer(n)
         self.k = Integer(k)
+        alphabet = OrderedAlphabet(range(1,self.n+1))
+        super(LyndonWords_nk,self).__init__(alphabet,self.k)
 
     def __repr__(self):
         """
@@ -213,19 +233,11 @@
             sage: all([lw in LW33 for lw in LW33])
             True
         """
-
-        #Get the content of x and create
-        c = filter(lambda x: x!=0, Word(x).evaluation())
-
-        #Change x to the "standard form"
-        d = {}
-        for i in x:
-            d[i] = 1
-        temp = [i for i in sorted(d.keys())]
-        new_x = map( lambda i: temp.index(i)+1, x )
-
-        #Check to see if it is in the Lyndon
-        return new_x in LyndonWords_evaluation(c)
+        try:
+            w = LyndonWord(x)
+            return w.length() == self.k and len(set(w)) <= self.n
+        except ValueError:
+            return False
 
     def cardinality(self):
         """
@@ -247,14 +259,7 @@
         TESTS::
         
             sage: LyndonWords(3,3).list() # indirect doctest
-            [[1, 1, 2],
-             [1, 1, 3],
-             [1, 2, 2],
-             [1, 2, 3],
-             [1, 3, 2],
-             [1, 3, 3],
-             [2, 2, 3],
-             [2, 3, 3]]
+            [word: 112, word: 113, word: 122, word: 123, word: 132, word: 133, word: 223, word: 233]
         """
         for c in IntegerVectors(self.k, self.n):
             cf = filter(lambda x: x != 0, c)
@@ -263,8 +268,7 @@
                 if c[i] != 0:
                     nonzero_indices.append(i)
             for lw in LyndonWords_evaluation(cf):
-                yield map(lambda x: nonzero_indices[x-1]+1, lw)
-
+                yield LyndonWord(map(lambda x: nonzero_indices[x-1]+1, lw), check=False)
 
 def StandardBracketedLyndonWords(n, k):
     """
@@ -336,7 +340,6 @@
         """
         for lw in LyndonWords_nk(self.n, self.k):
             yield standard_bracketing(lw)
-            
 
 def standard_bracketing(lw):
     """
@@ -355,13 +358,9 @@
          [2, [2, 3]],
          [[2, 3], 3]]
     """
-    n = max(lw)
-    k = len(lw)
-    
     if len(lw) == 1:
         return lw[0]
         
     for i in range(1,len(lw)):
-        if lw[i:] in LyndonWords(n,k):
+        if lw[i:] in LyndonWords():
             return [ standard_bracketing( lw[:i] ), standard_bracketing(lw[i:]) ]
-        
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/ribbon.py
--- a/sage/combinat/ribbon.py	Thu Jul 09 15:14:36 2009 -0700
+++ b/sage/combinat/ribbon.py	Fri Jul 17 23:25:52 2009 +0200
@@ -222,10 +222,10 @@
             sage: Ribbon([[1,2],[3,4]]).evaluation()
             [1, 1, 1, 1]
         """
-
-        return self.to_word().evaluation()
-
-    
+        ed = self.to_word().evaluation_dict()
+        entries = ed.keys()
+        m = max(entries) + 1 if entries else -1
+        return [ed.get(k,0) for k in range(1,m)]
 
 def from_shape_and_word(shape, word):
     """
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/ribbon_tableau.py
--- a/sage/combinat/ribbon_tableau.py	Thu Jul 09 15:14:36 2009 -0700
+++ b/sage/combinat/ribbon_tableau.py	Fri Jul 17 23:25:52 2009 +0200
@@ -20,7 +20,6 @@
 import skew_tableau, permutation, partition, skew_partition
 from sage.rings.all import QQ, ZZ
 import functools
-from sage.combinat.words.words import Words
 
 def RibbonTableau(rt=None, expr=None):
     """
@@ -88,10 +87,11 @@
             sage: R.to_word()
             word: 2041100030
         """
+        from sage.combinat.words.word import Word
         w = []
         for row in reversed(self):
             w += row
-        return Words(alphabet="natural numbers")(w)
+        return Word(w)
 
     def evaluation(self):
         """
@@ -102,9 +102,10 @@
             sage: RibbonTableau([[0, 0, 3, 0], [1, 1, 0], [2, 0, 4]]).evaluation()
             [2, 1, 1, 1]
         """
-        w = [i for i in self.to_word() if i != 0]
-        word = Words(alphabet="positive integers")(w)
-        return word.evaluation()
+        ed = self.to_word().evaluation_dict()
+        entries = ed.keys()
+        m = max(entries) + 1 if entries else -1
+        return [ed.get(k,0) for k in range(1,m)]
 
 def from_expr(l):
     """
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/sf/ns_macdonald.py
--- a/sage/combinat/sf/ns_macdonald.py	Thu Jul 09 15:14:36 2009 -0700
+++ b/sage/combinat/sf/ns_macdonald.py	Fri Jul 17 23:25:52 2009 +0200
@@ -2,7 +2,7 @@
 Non-symmetric Macdonald Polynomials
 """
 from sage.combinat.combinat import CombinatorialObject, CombinatorialClass
-from sage.combinat.words.words import Words
+from sage.combinat.words.word import Word
 from sage.combinat.combination import Combinations
 from sage.combinat.permutation import Permutation
 from sage.rings.all import QQ, PolynomialRing, prod
@@ -368,7 +368,10 @@
             sage: a.weight()
             [1, 2, 1, 1, 2, 1]
         """
-        return self.reading_word().evaluation()
+        ed = self.reading_word().evaluation_dict()
+        entries = ed.keys()
+        m = max(entries) + 1 if entries else -1
+        return [ed.get(k,0) for k in range(1,m)]
 
     def descents(self):
         """
@@ -444,7 +447,7 @@
             word: 25465321
         """
         w = [self[i,j] for i,j in self.reading_order() if j > 0]
-        return Words(alphabet="positive integers")(w)
+        return Word(w)
 
                        
     def inversions(self):
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/skew_tableau.py
--- a/sage/combinat/skew_tableau.py	Thu Jul 09 15:14:36 2009 -0700
+++ b/sage/combinat/skew_tableau.py	Fri Jul 17 23:25:52 2009 +0200
@@ -274,7 +274,10 @@
             sage: SkewTableau([[1,2],[3,4]]).evaluation()
             [1, 1, 1, 1]
         """
-        return self.to_word().evaluation()
+        ed = self.to_word().evaluation_dict()
+        entries = ed.keys()
+        m = max(entries) + 1 if entries else -1
+        return [ed.get(k,0) for k in range(1,m)]
 
     weight = evaluation
 
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/tableau.py
--- a/sage/combinat/tableau.py	Thu Jul 09 15:14:36 2009 -0700
+++ b/sage/combinat/tableau.py	Fri Jul 17 23:25:52 2009 +0200
@@ -28,7 +28,6 @@
 from sage.misc.misc import uniq
 from combinat import CombinatorialClass, CombinatorialObject, InfiniteAbstractCombinatorialClass
 import __builtin__
-from sage.combinat.words.words import Words
 
 def Tableau(t):
     """
@@ -217,10 +216,11 @@
             sage: Tableau([[1, 4, 6], [2, 5], [3]]).to_word_by_row()
             word: 325146
         """
+        from sage.combinat.words.word import Word
         w = []
         for row in reversed(self):
             w += row
-        return Words(alphabet="positive integers")(w)
+        return Word(w)
 
     def to_word_by_column(self):
         """
@@ -233,11 +233,12 @@
             sage: Tableau([[1, 4, 6], [2, 5], [3]]).to_word_by_column()
             word: 321546
         """
+        from sage.combinat.words.word import Word
         w = []
         conj = self.conjugate()
         for row in conj:
             w += list(reversed(row))
-        return Words(alphabet="positive integers")(w)
+        return Word(w)
 
     def to_word(self):
         """
@@ -399,7 +400,10 @@
             sage: Tableau([[1,2],[3,4]]).evaluation()
             [1, 1, 1, 1]
         """
-        return self.to_word().evaluation()
+        ed = self.to_word().evaluation_dict()
+        entries = ed.keys()
+        m = max(entries) + 1 if entries else -1
+        return [ed.get(k,0) for k in range(1,m)]
 
     weight = evaluation
 
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/words/all.py
--- a/sage/combinat/words/all.py	Thu Jul 09 15:14:36 2009 -0700
+++ b/sage/combinat/words/all.py	Fri Jul 17 23:25:52 2009 +0200
@@ -1,5 +1,6 @@
 from alphabet import Alphabet
 from morphism import WordMorphism
-from word import Word, WordOptions
+from word import Word
+from word_options import WordOptions
 from word_generators import words
 from words import Words
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/words/alphabet.py
--- a/sage/combinat/words/alphabet.py	Thu Jul 09 15:14:36 2009 -0700
+++ b/sage/combinat/words/alphabet.py	Fri Jul 17 23:25:52 2009 +0200
@@ -1,6 +1,21 @@
 # coding=utf-8
-"""
+r"""
 Alphabets
+
+AUTHORS:
+
+    - Franco Saliola (2008-12-17) : merged into sage
+
+EXAMPLES::
+
+    sage: Alphabet("ab")
+    Ordered Alphabet ['a', 'b']
+    sage: Alphabet([0,1,2])
+    Ordered Alphabet [0, 1, 2]
+    sage: Alphabet(name="PP")
+    Ordered Alphabet of Positive Integers
+    sage: Alphabet(name="NN")
+    Ordered Alphabet of Natural Numbers
 """
 #*****************************************************************************
 #       Copyright (C) 2008 Franco Saliola <saliola@gmail.com>
@@ -20,9 +35,9 @@
 def Alphabet(data=None, name=None):
     r"""
     Returns an object representing an ordered alphabet.
-    
+
     EXAMPLES::
-    
+
         sage: Alphabet("ab")
         Ordered Alphabet ['a', 'b']
         sage: Alphabet([0,1,2])
@@ -36,6 +51,8 @@
         sage: Alphabet(name="NN")
         Ordered Alphabet of Natural Numbers
     """
+    if isinstance(data, CombinatorialClass):
+        return data
     if data is None and name is None:
         raise TypeError, "provide at least one argument"
     if data is None:
@@ -57,7 +74,20 @@
     r"""
     Generic class for ordered alphabets.
     """
-    pass
+    def string_rep(self):
+        r"""
+        Returns the string representation of the alphabet.
+        
+        TESTS::
+        
+            sage: from sage.combinat.words.alphabet import OrderedAlphabet_Finite
+            sage: OrderedAlphabet_Finite([1, 3, 2]).string_rep()
+            doctest:1: DeprecationWarning: string_rep is deprecated, use __repr__ instead!
+            'Ordered Alphabet [1, 3, 2]'
+        """
+        from sage.misc.misc import deprecation
+        deprecation("string_rep is deprecated, use __repr__ instead!")
+        return self.__repr__()
 
 class OrderedAlphabet_Finite(OrderedAlphabet_class):
     def __init__(self, alphabet):
@@ -65,11 +95,12 @@
         Builds an ordered alphabet from an iterable. The order is that
         given by the order the items appear in the iterable. There must be
         no duplicates.
-        
-        NOTE: The alphabet is expanded in memory and stored as a list.
-        
+
+        NOTE:
+            The alphabet is expanded in memory and stored as a list.
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_Finite
             sage: A = OrderedAlphabet_Finite([0,1,2])
             sage: A == loads(dumps(A))
@@ -77,9 +108,9 @@
             sage: A = OrderedAlphabet_Finite("abc")
             sage: A == loads(dumps(A))
             True
-        
+
         TESTS::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_Finite
             sage: OrderedAlphabet_Finite('aba')
             Traceback (most recent call last):
@@ -116,18 +147,36 @@
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_Finite
             sage: type(iter(OrderedAlphabet_Finite("abc")))
             <type 'generator'>
-            sage: list(OrderedAlphabet_Finite("abc"))       # indirect doctest 
+            sage: list(OrderedAlphabet_Finite("abc"))       # indirect doctest
             ['a', 'b', 'c']
-            sage: list(OrderedAlphabet_Finite([10, 17, 3])) # indirect doctest 
+            sage: list(OrderedAlphabet_Finite([10, 17, 3])) # indirect doctest
             [10, 17, 3]
         """
         for a in self._alphabet:
             yield a
 
+    def __len__(self):
+        """
+        EXAMPLES::
+
+            sage: from sage.combinat.words.alphabet import OrderedAlphabet_Finite
+            sage: A = OrderedAlphabet_Finite([0,1,2])
+            sage: len(A)
+            3
+            sage: B = OrderedAlphabet_Finite("abc")
+            sage: len(B)
+            3
+            sage: len(OrderedAlphabet_Finite(""))
+            0
+            sage: len(OrderedAlphabet_Finite(range(25)))
+            25
+        """
+        return len(self._alphabet)
+
     def __contains__(self, a):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_Finite
             sage: A = OrderedAlphabet_Finite([0,1,2])
             sage: 2 in A
@@ -147,11 +196,12 @@
 
     def __le__(self, other):
         r"""
-        Returns True if the elements of self appear among the elements of
-        other in the same respective order, and False otherwise.
+        Returns ``True`` if the elements of ``self`` appear among the 
+        elements of ``other`` in the same respective order, and ``False`` 
+        otherwise.
         
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_Finite
             sage: OrderedAlphabet_Finite('abc') <= OrderedAlphabet_Finite('daefbgc')
             True
@@ -168,13 +218,14 @@
 
     def __ge__(self, other):
         r"""
-        Returns True if the elements of other appear among the elements of
-        self in the same respective order, and False otherwise.
+        Returns ``True`` if the elements of ``other`` appear among the 
+        elements of ``self`` in the same respective order, and ``False`` 
+        otherwise.
         
         The ordering of the alphabet is taken into consideration.
         
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_Finite
             sage: OrderedAlphabet_Finite('abc') >= OrderedAlphabet_Finite('daefbgc')
             False
@@ -189,38 +240,20 @@
         """
         return other.list() == self.filter(lambda a: a in other).list()
 
-    def string_rep(self):
-        r"""
-        Returns the string representation of the alphabet.
-        
-        TESTS::
-        
-            sage: from sage.combinat.words.alphabet import OrderedAlphabet_Finite
-            sage: OrderedAlphabet_Finite('cba').string_rep()
-            "['c', 'b', 'a']"
-            sage: OrderedAlphabet_Finite([1, 3, 2]).string_rep()
-            '[1, 3, 2]'
-        """
-        return "[%s]" % ', '.join(itertools.imap(repr, self))
-
     def rank(self, letter):
         r"""
-        Returns the index of letter in self.
+        Returns the index of ``letter`` in ``self``.
         
         INPUT:
-        
-        
-        -  ``letter`` - a letter contained in this alphabet
-        
+
+        - ``letter`` - a letter contained in this alphabet
         
         OUTPUT:
-        
-        
-        -  ``integer`` - the integer mapping for the letter
-        
+
+        integer -- the integer mapping for the letter
         
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_Finite
             sage: OrderedAlphabet_Finite('abcd').rank('a')
             0
@@ -242,18 +275,18 @@
 
     def unrank(self, n):
         r"""
-        Returns the letter in position n of the alphabet self.
+        Returns the letter in position ``n`` of the alphabet ``self``.
         
         INPUT:
-        
-        
+
         -  ``n`` - a nonnegative integer
         
-        
-        OUTPUT: the (n+1)-th object output by iter(self)
+        OUTPUT:
+
+        letter -- the (n+1)-th object output by ``iter(self)``
         
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_Finite
             sage: OrderedAlphabet_Finite('abcd').unrank(0)
             'a'
@@ -269,11 +302,11 @@
 class OrderedAlphabet_Infinite(OrderedAlphabet_class):
     def __le__(self, other):
         r"""
-        Returns NotimplementedError since it is not clear how to define
+        Returns ``NotimplementedError`` since it is not clear how to define
         this for infinite ordered alphabets.
-        
+
         TESTS::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_Infinite
             sage: A1 = OrderedAlphabet_Infinite()
             sage: A2 = OrderedAlphabet_Infinite()
@@ -286,11 +319,11 @@
 
     def __ge__(self, other):
         r"""
-        Returns NotimplementedError since it is not clear how to define
+        Returns ``NotimplementedError`` since it is not clear how to define
         this for infinite ordered alphabets.
-        
+
         TESTS::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_Infinite
             sage: A1 = OrderedAlphabet_Infinite()
             sage: A2 = OrderedAlphabet_Infinite()
@@ -303,12 +336,14 @@
 
     def cardinality(self):
         r"""
-        Return the number of elements in self.
+        Returns the number of elements in ``self``.
         
-        OUTPUT: +Infinity
+        OUTPUT:
+
+        +Infinity
         
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_Infinite
             sage: OrderedAlphabet_Infinite().cardinality()
             +Infinity
@@ -317,11 +352,11 @@
 
     def list(self):
         r"""
-        Returns NotImplementedError since we cannot list all the
+        Returns ``NotImplementedError`` since we cannot list all the
         nonnegative integers.
-        
+
         TESTS::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_Infinite
             sage: OrderedAlphabet_Infinite().list()
             Traceback (most recent call last):
@@ -332,10 +367,11 @@
 
 class OrderedAlphabet_NaturalNumbers(OrderedAlphabet_Infinite):
     r"""
-    The alphabet of nonnegative integers, ordered in the usual way.
-    
+    The alphabet of nonnegative integers,
+    ordered in the usual way.
+
     TESTS::
-    
+
         sage: from sage.combinat.words.alphabet import OrderedAlphabet_NaturalNumbers
         sage: NN = OrderedAlphabet_NaturalNumbers()
         sage: NN == loads(dumps(NN))
@@ -344,7 +380,7 @@
     def __repr__(self):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_NaturalNumbers
             sage: OrderedAlphabet_NaturalNumbers().__repr__()
             'Ordered Alphabet of Natural Numbers'
@@ -354,7 +390,7 @@
     def __iter__(self):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_NaturalNumbers
             sage: it = iter(OrderedAlphabet_NaturalNumbers())
             sage: type(it)
@@ -372,7 +408,7 @@
     def __contains__(self, a):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_NaturalNumbers
             sage: A = OrderedAlphabet_NaturalNumbers()
             sage: 2 in A
@@ -388,45 +424,29 @@
         """
         return isinstance(a, (int, Integer)) and a >= 0
 
-    def string_rep(self):
-        r"""
-        Returns the string representation of the alphabet.
-        
-        TESTS::
-        
-            sage: from sage.combinat.words.alphabet import OrderedAlphabet_NaturalNumbers
-            sage: OrderedAlphabet_NaturalNumbers().string_rep()
-            'Natural Numbers'
-        """
-        return "Natural Numbers"
-
     def rank(self, letter):
         r"""
-        Returns the index of letter in self.
+        Returns the index of letter in ``self``.
         
         INPUT:
-        
-        
-        -  ``letter`` - a letter contained in this alphabet
-        
+
+        - ``letter`` - a letter contained in this alphabet
         
         OUTPUT:
-        
-        
-        -  ``integer`` - the integer mapping for the letter
-        
+
+        integer -- the integer mapping for the letter
         
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_NaturalNumbers
             sage: NN = OrderedAlphabet_NaturalNumbers()
             sage: NN.rank(0)
             0
             sage: NN.rank(17)
             17
-        
+
         TESTS::
-        
+
             sage: NN.rank(-1)
             Traceback (most recent call last):
             ...
@@ -443,31 +463,28 @@
 
     def unrank(self, n):
         r"""
-        Returns the letter in position n in self, which in this case is n.
+        Returns the letter in position ``n`` in ``self``, which in this case 
+        is ``n``.
         
         INPUT:
-        
-        
-        -  ``n`` - nonnegative integer
-        
+
+        - ``n`` - nonnegative integer
         
         OUTPUT:
-        
-        
-        -  ``n`` - nonnegative integer
-        
-        
+
+        - ``n`` - nonnegative integer
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_NaturalNumbers
             sage: NN = OrderedAlphabet_NaturalNumbers()
             sage: NN.unrank(0)
             0
             sage: NN.unrank(17)
             17
-        
+
         TESTS::
-        
+
             sage: NN.unrank(-1)
             Traceback (most recent call last):
             ...
@@ -484,18 +501,18 @@
 
     def next(self, n):
         r"""
-        Returns the letter following n in the alphabet self.
+        Returns the letter following ``n`` in the alphabet ``self``.
         
         INPUT:
-        
-        
-        -  ``n`` - nonnegative integer
-        
-        
-        OUTPUT: n+1
-        
+
+        - ``n`` - nonnegative integer
+            
+        OUTPUT:
+
+            n+1
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_NaturalNumbers
             sage: NN = OrderedAlphabet_NaturalNumbers()
             sage: NN.next(0)
@@ -514,10 +531,11 @@
 
 class OrderedAlphabet_PositiveIntegers(OrderedAlphabet_Infinite):
     r"""
-    The alphabet of nonnegative integers, ordered in the usual way.
-    
+    The alphabet of nonnegative integers,
+    ordered in the usual way.
+
     TESTS::
-    
+
         sage: from sage.combinat.words.alphabet import OrderedAlphabet_PositiveIntegers
         sage: PP = OrderedAlphabet_PositiveIntegers()
         sage: PP == loads(dumps(PP))
@@ -526,7 +544,7 @@
     def __repr__(self):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_PositiveIntegers
             sage: OrderedAlphabet_PositiveIntegers().__repr__()
             'Ordered Alphabet of Positive Integers'
@@ -536,7 +554,7 @@
     def __iter__(self):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_PositiveIntegers
             sage: it = iter(OrderedAlphabet_PositiveIntegers())
             sage: type(it)
@@ -554,7 +572,7 @@
     def __contains__(self, a):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_PositiveIntegers
             sage: A = OrderedAlphabet_PositiveIntegers()
             sage: 2 in A
@@ -570,40 +588,28 @@
         """
         return isinstance(a, (int, Integer)) and a > 0
 
-    def string_rep(self):
-        r"""
-        Returns the string representation of the alphabet.
-        
-        TESTS::
-        
-            sage: from sage.combinat.words.alphabet import OrderedAlphabet_PositiveIntegers
-            sage: OrderedAlphabet_PositiveIntegers().string_rep()
-            'Positive Integers'
-        """
-        return "Positive Integers"
-
     def rank(self, letter):
         r"""
-        Returns the index of letter in self.
+        Returns the index of ``letter`` in ``self``.
         
         INPUT:
+
+        - ``letter`` - a positive integer
         
-        
-        -  ``letter`` - a positive integer
-        
-        
-        OUTPUT: letter-1
+        OUTPUT:
+
+            letter-1
         
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_PositiveIntegers
             sage: OrderedAlphabet_PositiveIntegers().rank(1)
             0
             sage: OrderedAlphabet_PositiveIntegers().rank(8)
             7
-        
+
         TESTS::
-        
+
             sage: OrderedAlphabet_PositiveIntegers().rank(-1)
             Traceback (most recent call last):
             ...
@@ -616,19 +622,19 @@
 
     def unrank(self, i):
         r"""
-        Returns the i-th letter in self, where the first letter is the 0-th
-        letter.
+        Returns the ``i``-th letter in ``self``, where the first letter is 
+        the 0-th letter.
         
         INPUT:
+
+        - ``i`` - an integer
         
-        
-        -  ``i`` - an integer
-        
-        
-        OUTPUT: i+1
+        OUTPUT:
+
+            i+1
         
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_PositiveIntegers
             sage: OrderedAlphabet_PositiveIntegers().unrank(0)
             1
@@ -644,18 +650,18 @@
 
     def next(self, n):
         r"""
-        Returns the letter following n in the alphabet self.
+        Returns the letter following ``n`` in the alphabet ``self``.
         
         INPUT:
-        
-        
-        -  ``n`` - positive integer
-        
-        
-        OUTPUT: n+1
-        
+
+        - ``n`` - positive integer
+            
+        OUTPUT:
+
+            n+1
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.alphabet import OrderedAlphabet_PositiveIntegers
             sage: PP = OrderedAlphabet_PositiveIntegers()
             sage: PP.next(1)
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/words/morphism.py
--- a/sage/combinat/words/morphism.py	Thu Jul 09 15:14:36 2009 -0700
+++ b/sage/combinat/words/morphism.py	Fri Jul 17 23:25:52 2009 +0200
@@ -1,9 +1,81 @@
 # coding=utf-8
-"""
-Word morphisms
+r"""
+Word morphisms/substitutions
+
+This modules implements morphisms over finite and infinite words.
+
+AUTHORS:
+
+- Sebastien Labbe (2007-06-01): initial version
+- Sebastien Labbe (2008-07-01): merged into sage-words
+- Sebastien Labbe (2008-12-17): merged into sage
+- Sebastien Labbe (2009-02-03): words next generation
+
+EXAMPLES:
+
+Creation of a morphism from a dictionary or a string::
+
+    sage: n = WordMorphism({0:[0,2,2,1],1:[0,2],2:[2,2,1]})
+
+::
+
+    sage: m = WordMorphism('x->xyxsxss,s->xyss,y->ys')
+
+::
+
+    sage: n
+    Morphism from Words over Ordered Alphabet [0, 1, 2] to Words over Ordered Alphabet [0, 1, 2]
+    sage: m
+    Morphism from Words over Ordered Alphabet ['s', 'x', 'y'] to Words over Ordered Alphabet ['s', 'x', 'y']
+
+The codomain may be specified::
+
+    sage: WordMorphism({0:[0,2,2,1],1:[0,2],2:[2,2,1]}, codomain=Words([0,1,2,3,4])) 
+    Morphism from Words over Ordered Alphabet [0, 1, 2] to Words over Ordered Alphabet [0, 1, 2, 3, 4]
+
+Power of a morphism::
+
+    sage: print n^2
+    WordMorphism: 0->022122122102, 1->0221221, 2->22122102
+
+Image under a morphism::
+
+    sage: m('y')
+    word: ys
+    sage: m('xxxsy')
+    word: xyxsxssxyxsxssxyxsxssxyssys
+
+Iterated image under a morphism::
+
+    sage: m('y', 3)
+    word: ysxyssxyxsxssysxyssxyss
+
+Infinite fixed point of morphism::
+
+    sage: fix = m.fixed_point('x')
+    sage: fix
+    Fixed point beginning with 'x' of the morphism WordMorphism: s->xyss, x->xyxsxss, y->ys
+    sage: fix.length()
+    +Infinity
+    sage: fix[100:]
+    word: ysxyxsxssxyssxyxsxssxyssxyssxyxsxssysxys...
+
+Incidence matrix::
+
+    sage: matrix(m)
+    [2 3 1]
+    [1 3 0]
+    [1 1 1]
+
+Many other functionalities...::
+
+    sage: m.is_identity()
+    False
+    sage: m.is_endomorphism()
+    True
 """
 #*****************************************************************************
-#       Copyright (C) 2008 Sébastien Labbé <slabqc@gmail.com>
+#       Copyright (C) 2008 Sebastien Labbe <slabqc@gmail.com>
 #
 #  Distributed under the terms of the GNU General Public License version 2 (GPLv2)
 #
@@ -11,21 +83,20 @@
 #
 #                  http://www.gnu.org/licenses/
 #*****************************************************************************
-from utils import isint, is_iterable
 from itertools import imap, ifilterfalse
 from sage.structure.sage_object import SageObject
-from sage.rings.infinity import infinity
+from sage.rings.infinity import Infinity
 from sage.matrix.constructor import Matrix
 from sage.rings.integer_ring import IntegerRing
-from sage.misc.latex import latex
-from sage.combinat.words.word import is_FiniteWord, FiniteWord_over_OrderedAlphabet
-from sage.combinat.words.words import is_Words, Words
-from sage.combinat.words.alphabet import OrderedAlphabet
+from sage.rings.integer import Integer
+from sage.combinat.words.word import FiniteWord_class
+from sage.combinat.words.words import Words_all, Words
+from sage.sets.set import Set
 
 class WordMorphism(SageObject):
     r"""
     TESTS::
-    
+
         sage: wm = WordMorphism('a->ab,b->ba')
         sage: wm == loads(dumps(wm))
         True
@@ -36,10 +107,8 @@
         
         EXAMPLES:
         
-        1. If data is a str
-        
-        ::
-        
+        1. If data is a str::
+
             sage: print WordMorphism('a->ab,b->ba')
             WordMorphism: a->ab, b->ba
             sage: print WordMorphism('a->ab,b->ba')
@@ -52,14 +121,14 @@
             WordMorphism: (->(), )->)(
             sage: print WordMorphism('a->53k,b->y5?,$->49i')
             WordMorphism: $->49i, a->53k, b->y5?
-        
+            
         An erasing morphism::
-        
+
             sage: print WordMorphism('a->ab,b->')
             WordMorphism: a->ab, b->
-        
+            
         Use the arrows ('->') correctly::
-        
+
             sage: WordMorphism('a->ab,b-')
             Traceback (most recent call last):
             ...
@@ -72,50 +141,46 @@
             Traceback (most recent call last):
             ...
             ValueError: The second and third characters must be '->' (not '-]')
-        
+            
         Each letter must be defined only once::
-        
+
             sage: WordMorphism('a->ab,a->ba')
             Traceback (most recent call last):
             ...
             ValueError: The image of 'a' is defined twice.
-        
-        2. From a dictionary.
-        
-        ::
-        
+            
+        2. From a dictionary::
+
             sage: print WordMorphism({"a":"ab","b":"ba"})
             WordMorphism: a->ab, b->ba
             sage: print WordMorphism({2:[4,5,6],3:[1,2,3]})  
             WordMorphism: 2->456, 3->123
             sage: print WordMorphism({'a':['a',6,'a'],6:[6,6,6,'a']})
             WordMorphism: 6->666a, a->a6a
-        
-        The image of a letter can be a set, but the order is not
+            
+        The image of a letter can be a set, but the order is not 
         preserved::
-        
+
             sage: print WordMorphism({2:[4,5,6],3:set([4,1,8])}) #random results
             WordMorphism: 2->456, 3->814
-        
-        If the image of a letter is not iterable, it is considered as a
+            
+        If the image of a letter is not iterable, it is considered as a 
         letter::
-        
+
             sage: print WordMorphism({0:1, 1:0})
             WordMorphism: 0->1, 1->0
             sage: print WordMorphism({0:123, 1:789})
             WordMorphism: 0->123, 1->789
             sage: print WordMorphism({2:[4,5,6], 3:123})    
             WordMorphism: 2->456, 3->123
-        
-        3. From a WordMorphism
-        
-        ::
-        
+            
+        3. From a WordMorphism::
+
             sage: print WordMorphism(WordMorphism('a->ab,b->ba'))
             WordMorphism: a->ab, b->ba
-        
+
         TESTS::
-        
+
             sage: print WordMorphism(',,,a->ab,,,b->ba,,')
             WordMorphism: a->ab, b->ba
         """
@@ -132,28 +197,30 @@
             if codomain is None:
                 codomain = self._build_codomain(data)
 
-            if not is_Words(codomain):
+            if not isinstance(codomain,Words_all):
                 raise TypeError, "the codomain must be a Words domain"
             self._codomain = codomain
             
             self._morph = {}
             
             dom_alph = list()
-            cod = self._codomain
             for (key,val) in data.iteritems():
                 dom_alph.append(key)
-                self._morph[key] = cod(val)
+                if val in codomain.alphabet():
+                    self._morph[key] = codomain([val])
+                else:
+                    self._morph[key] = codomain(val)
             
             dom_alph.sort()
             self._domain = Words(dom_alph)
     
     def _build_dict(self, s):
         r"""
-        Parse the string input to WordMorphism and build the dictionary it
-        represents.
+        Parse the string input to WordMorphism and build the dictionary 
+        it represents.
         
         TESTS::
-        
+
             sage: wm = WordMorphism('a->ab,b->ba')
             sage: wm._build_dict('a->ab,b->ba') == {'a': 'ab', 'b': 'ba'}
             True
@@ -185,11 +252,13 @@
 
     def _build_codomain(self, data):
         r"""
-        Returns a Words domain containing all the letter in the keys of
+        Returns a Words domain containing all the letter in the keys of 
         data (which must be a dictionary).
         
-        TESTS: 1. If the image of all the letters are iterable ::
-        
+        TESTS:
+            
+        If the image of all the letters are iterable::
+
             sage: wm = WordMorphism('a->ab,b->ba')
             sage: wm._build_codomain({'a': 'ab', 'b': 'ba'})
             Words over Ordered Alphabet ['a', 'b']
@@ -199,10 +268,10 @@
             Words over Ordered Alphabet [1, 2, 3, 4, 5, 6]
             sage: wm._build_codomain({2:[4,5,6],3:set([4,1,8])})         
             Words over Ordered Alphabet [1, 4, 5, 6, 8]
-        
-        2. If the image of a letter is not iterable, it is considered as a
-        letter::
-        
+
+        If the image of a letter is not iterable, it is considered as
+        a letter::
+
             sage: wm._build_codomain({2:[4,5,6],3:123})
             Words over Ordered Alphabet [4, 5, 6, 123]
             sage: wm._build_codomain({0:1, 1:0, 2:2})
@@ -210,18 +279,19 @@
         """
         codom_alphabet = set()
         for key,val in data.iteritems():
-            if is_iterable(val):
-                codom_alphabet.update(val)
-            else:
-                codom_alphabet.add(val)
+            try:
+                it = iter(val)
+            except:
+                it = [val]
+            codom_alphabet.update(it)
         return Words(sorted(codom_alphabet))
         
     def __eq__(self, other):
         r"""
-        Returns True if self is equal to other.
+        Returns ``True`` if ``self`` is equal to ``other``.
         
         EXAMPLES::
-        
+
             sage: n = WordMorphism('a->a,b->aa,c->aaa')
             sage: n**3 == n**1
             True
@@ -236,6 +306,8 @@
             sage: m == o
             False
         """
+        if not isinstance(other, WordMorphism):
+            return False
         return self._morph == other._morph
     
     def __repr__(self):
@@ -243,7 +315,7 @@
         Returns the morphism in str (for display).
         
         EXAMPLES::
-        
+
             sage: WordMorphism('a->ab,b->ba')
             Morphism from Words over Ordered Alphabet ['a', 'b'] to Words over Ordered Alphabet ['a', 'b']
             sage: d = {0:[0,1],1:[1,0]}
@@ -257,7 +329,7 @@
         Returns the morphism in str (for display).
         
         EXAMPLES::
-        
+
             sage: print WordMorphism('a->ab,b->ba')
             WordMorphism: a->ab, b->ba
             sage: print WordMorphism('b->ba,a->ab')    
@@ -272,115 +344,109 @@
     
     def __call__(self, w, order=1):
         r"""
-        Returns the image of w under self to the given order.
+        Returns the image of ``w`` under ``self`` to the given ``order``.
         
         INPUT:
+
+        -  ``w`` - finite word in the domain of ``self``, must be 
+           of length one if order is ``Infinity``
+        -  ``order`` - integer or plus ``Infinity`` (default: 1)
+            
+        OUTPUT:
+
+        -  ``word`` - order-th iterated image under ``self`` of ``w``
         
+        EXAMPLES: 
         
-        -  ``w`` - finite word in the domain of self, must be
-           of length one if order is infinity
-        
-        -  ``order`` - integer or plus infinity (default: 1)
-        
-        
-        OUTPUT:
-        
-        
-        -  ``word`` - order-th iterated image under self of w
-        
-        
-        EXAMPLES: The image of a word under a morphism:
+        The image of a word under a morphism:
         
         1. The image of a finite word under a morphism::
-        
+
             sage: tm = WordMorphism ('a->ab,b->ba')
             sage: tm('a')
             word: ab
             sage: tm('aabababb')
             word: ababbaabbaabbaba
-        
+
         2. The iterated image of a word::
-        
+
             sage: tm('a', 2)
             word: abba
             sage: tm('aba', 3)
             word: abbabaabbaababbaabbabaab
-        
+            
         3. The infinitely iterated image of a letter::
-        
+
             sage: tm('a', oo)
             Fixed point beginning with 'a' of the morphism WordMorphism: a->ab, b->ba
-        
+
         4. The image of an infinite word::
-        
+
             sage: t = words.ThueMorseWord()
             sage: n = WordMorphism({0:[0, 1], 1:[1, 0]})
             sage: n(t)
-            Infinite word over [0, 1]
+            word: 0110100110010110100101100110100110010110...
             sage: n(t, 3)
-            Infinite word over [0, 1]
-            sage: n(t)[:39]
-            word: 011010011001011010010110011010011001011
+            word: 0110100110010110100101100110100110010110...
             sage: n(t)[:1000] == t[:1000]
             True
-        
+
         ::
-        
+
             sage: w = words.FibonacciWord()
             sage: m = WordMorphism({0:'a', 1:'b'})
             sage: m(w)
-            Infinite word over ['a', 'b']
+            word: abaababaabaababaababaabaababaabaababaaba...
             sage: f = words.FibonacciWord('ab')
             sage: f[:1000] == m(w)[:1000]
             True
-        
+
         ::
-        
+
             sage: w = words.FibonacciWord("ab")
             sage: m = WordMorphism('a->01,b->101')
             sage: m(w)
-            Infinite word over ['0', '1']
-            sage: m(w)[:39]
-            word: 011010101101011010101101010110101101010
-        
-        The word must be in the domain of self::
-        
+            word: 0110101011010110101011010101101011010101...
+
+        The word must be in the domain of ``self``::
+
             sage: tm('0021')  
             Traceback (most recent call last):
             ...
-            TypeError: cannot apply to incompatible set
-        
-        The order must be a positive integer or plus infinity::
-        
+            ValueError: 0 not in alphabet!
+
+
+        The order must be a positive integer or plus Infinity::
+
             sage: tm('a', -1)
             Traceback (most recent call last):
             ...
-            TypeError: order (-1) must be a positive integer or plus infinity
+            TypeError: order (-1) must be a positive integer or plus Infinity
             sage: tm('a', 6.7)
             Traceback (most recent call last):
             ...
-            TypeError: order (6.70000000000000) must be a positive integer or plus infinity
-        
+            TypeError: order (6.70000000000000) must be a positive integer or plus Infinity
+
         Infinitely iterated image of a word is defined only for those of
         length one::
-        
+
             sage: tm('aba',oo)
             Traceback (most recent call last):
             ...
             TypeError: For infinite powers, the length of the word must be 1 (not 3)
-        
-        self must be prolongable on the given letter for infinitely
-        iterated image::
-        
+
+        ``self`` must be prolongable on the given letter for infinitely iterated
+        image::
+
             sage: m = WordMorphism('a->ba,b->ab')
             sage: m('a', oo)
             Traceback (most recent call last):
             ...
             TypeError: self must be prolongable on a
-        
+
         TESTS::
-        
-            sage: for i in range(8):
+
+            sage: for i in range(6):
             ...     tm('a', i)
             ...     
             word: a
@@ -389,49 +455,42 @@
             word: abbabaab
             word: abbabaabbaababba
             word: abbabaabbaababbabaababbaabbabaab
-            Finite word of length 64 over ['a', 'b']
-            Finite word of length 128 over ['a', 'b']
             sage: m = WordMorphism('a->,b->')
             sage: m('')
             word:
         """
-        try:
+        if self._morph.has_key(w):
+            w = self._domain([w])
+        else:
             w = self._domain(w)
-        except:
-            raise TypeError, "cannot apply to incompatible set"
         
-        if order is infinity:
-            if len(w) != 1:
-                raise TypeError, "For infinite powers, the length of the word must be 1 (not %s)"%len(w)
+        if order is Infinity:
+            if w.length() != 1:
+                raise TypeError, "For infinite powers, the length of the word must be 1 (not %s)"%w.length()
             return self.fixed_point(letter=w[0])
         
-        if not isint(order) or order < 0 :
-            raise TypeError, "order (%s) must be a positive integer or plus infinity" % order
+        if not isinstance(order, (int,Integer)) or order < 0 :
+            raise TypeError, "order (%s) must be a positive integer or plus Infinity" % order
         elif order == 0:
             return w
         elif order == 1:
-            if is_FiniteWord(w):
-                if len(w) == 1:
+            if isinstance(w, FiniteWord_class):
+                if w.length() == 1:
                     return self._morph[w[0]]
                 else:
-                    s = sum(Matrix(self)*Matrix(w.parikh_vector()).transpose())
-                    if isint(s):
-                        image_length = s
-                    else:
-                        image_length = s[0]
-                    return self.codomain()((x for y in w for x in self(y)),
-                                           part=slice(image_length))
+                    length = sum(self._morph[a].length() * b for (a,b) in w.evaluation_dict().iteritems())
+                    return self.codomain()((x for y in w for x in self._morph[y]), length=length)
             else:
-                return self.codomain()(x for y in w for x in self(y))
+                return self.codomain()((x for y in w for x in self._morph[y]), length=Infinity)
         elif order > 1:
             return self(self(w, order-1))
     
     def __mul__(self, other):
         r"""
-        Returns the morphism self\*other
+        Returns the morphism ``self``\*``other``.
         
         EXAMPLES::
-        
+
             sage: m = WordMorphism('a->ab,b->ba')
             sage: fibo = WordMorphism('a->ab,b->a')
             sage: print fibo*m
@@ -440,27 +499,36 @@
             WordMorphism: a->aba, b->ab
             sage: print m*fibo
             WordMorphism: a->abba, b->ab
-            sage: m = WordMorphism('a->ab,b->ba')
+
+        ::
+
             sage: n = WordMorphism('a->a,b->aa,c->aaa')
-            sage: p1 = n*m; p2 = m*n
+            sage: p1 = n*m
             sage: print p1
             WordMorphism: a->aaa, b->aaa
             sage: p1.domain()
             Words over Ordered Alphabet ['a', 'b']
             sage: p1.codomain()
             Words over Ordered Alphabet ['a']
+
+        ::
+
+            sage: p2 = m*n
             sage: print p2
             WordMorphism: a->ab, b->abab, c->ababab
             sage: p2.domain()
             Words over Ordered Alphabet ['a', 'b', 'c']
             sage: p2.codomain()
             Words over Ordered Alphabet ['a', 'b']
+
+        TESTS::
+
             sage: m = WordMorphism('a->b,b->c,c->a')
-            sage: WordMorphism('')*m            
+            sage: WordMorphism('')*m
             Traceback (most recent call last):
             ...
-            TypeError: cannot apply to incompatible set
-            sage: print m*WordMorphism('')
+            ValueError: b not in alphabet!
+            sage: print m * WordMorphism('')
             WordMorphism:
         """
         #TODO : Est-ce que c'est le comportement que l'on veut pour le produit 
@@ -469,33 +537,43 @@
     
     def __pow__(self, exp):
         r"""
-        Returns the power of self with exponent = exp.
+        Returns the power of ``self`` with exponent = ``exp``.
+
+        INPUT:
+
+        -  ``exp`` - a positive integer
         
         EXAMPLES::
-        
+
             sage: m = WordMorphism('a->ab,b->ba')
-            sage: m^1.5
-            Traceback (most recent call last):
-              ...
-            ValueError: exponent (1.50000000000000) must be an integer
+            sage: print m^1
+            WordMorphism: a->ab, b->ba
             sage: print m^2
             WordMorphism: a->abba, b->baab
             sage: print m^3
             WordMorphism: a->abbabaab, b->baababba
+
+        The exponent must be a positive integer::
+
+            sage: m^1.5
+            Traceback (most recent call last):
+            ...
+            ValueError: exponent (1.50000000000000) must be an integer
             sage: print m^-2
             Traceback (most recent call last):
-              ...
+            ...
             ValueError: exponent (-2) must be strictly positive
+
+        When ``self`` is not an endomorphism::
+
             sage: n = WordMorphism('a->ba,b->abc')
-            sage: print n^1
-            WordMorphism: a->ba, b->abc
             sage: n^2
             Traceback (most recent call last):
-              ...
-            TypeError: cannot apply to incompatible set
+            ...
+            ValueError: c not in alphabet!
         """
         #If exp is not an integer
-        if not isint(exp):
+        if not isinstance(exp, (int,Integer)):
             raise ValueError, "exponent (%s) must be an integer" %exp
 
         #If exp is negative
@@ -514,24 +592,103 @@
                 res *= self
             return res
             
+    def extend_by(self, other):
+        r"""
+        Returns ``self`` extended by ``other``.
+
+        Let `\varphi_1:A^*\rightarrow B^*` and `\varphi_2:C^*\rightarrow D^*`
+        be two morphisms. A morphism `\mu:(A\cup C)^*\rightarrow (B\cup D)^*`
+        corresponds to `\varphi_1` *extended by* `\varphi_2` if
+        `\mu(a)=\varphi_1(a)` if `a\in A` and `\mu(a)=\varphi_2(a)` otherwise.
+
+        INPUT:
+
+        -  ``other`` - a WordMorphism. 
+
+        OUTPUT:
+
+        WordMorphism
+        
+        EXAMPLES::
+
+            sage: m = WordMorphism('a->ab,b->ba')
+            sage: n = WordMorphism({0:1,1:0,'a':5})
+            sage: m.extend_by(n)
+            Morphism from Words over Ordered Alphabet ['a', 'b', 0, 1] to Words over Ordered Alphabet ['a', 'b', 0, 1]
+            sage: n.extend_by(m)
+            Morphism from Words over Ordered Alphabet ['a', 'b', 0, 1] to Words over Ordered Alphabet ['a', 'b', 0, 1, 5]
+            sage: m.extend_by(m)
+            Morphism from Words over Ordered Alphabet ['a', 'b'] to Words over Ordered Alphabet ['a', 'b']
+            sage: m.extend_by(WordMorphism({})) == m
+            True
+            sage: m.extend_by(WordMorphism('')) == m
+            True
+
+        TESTS::
+
+            sage: m.extend_by(4)
+            Traceback (most recent call last):
+            ...
+            TypeError: other (=4) is not a WordMorphism
+        """
+        if not isinstance(other, WordMorphism):
+            raise TypeError, "other (=%s) is not a WordMorphism"%other
+
+        nv = dict(other._morph)
+        for k,v in self._morph.iteritems():
+            nv[k] = v
+        return WordMorphism(nv)
+
+    def restrict_domain(self, alphabet):
+        r"""
+        Returns a restriction of ``self`` to the given alphabet.
+
+        INPUT:
+
+        - ``alphabet`` - an iterable
+
+        OUTPUT:
+
+        WordMorphism 
+        
+        EXAMPLES::
+
+            sage: m = WordMorphism('a->b,b->a')
+            sage: print m.restrict_domain('a')
+            WordMorphism: a->b
+            sage: print m.restrict_domain('') 
+            WordMorphism: 
+            sage: print m.restrict_domain('A')
+            WordMorphism: 
+            sage: print m.restrict_domain('Aa')
+            WordMorphism: a->b
+
+        The input alphabet must be iterable::
+
+            sage: print m.restrict_domain(66)  
+            Traceback (most recent call last):
+            ...
+            TypeError: 'sage.rings.integer.Integer' object is not iterable
+        """
+        return WordMorphism(dict((a, self(a)) for a in alphabet if a in self.domain().alphabet()))
+
     def _matrix_(self, R=None):
         r"""
-        Returns the incidence matrix of the morphism over the specified
-        ring.
-        
+        Returns the incidence matrix of the morphism over the specified ring.
+
         EXAMPLES::
-        
+
             sage: fibo = WordMorphism('a->ab,b->a')
             sage: tm = WordMorphism('a->ab,b->ba')
-            sage: Mfibo = (fibo)._matrix_(); Mfibo
+            sage: Mfibo = matrix(fibo); Mfibo
             [1 1]
             [1 0]
-            sage: Mtm = (tm)._matrix_(); Mtm
+            sage: Mtm = matrix(tm); Mtm
             [1 1]
             [1 1]
-            sage: Mtm * Mfibo == (tm*fibo)._matrix_()
+            sage: Mtm * Mfibo == matrix(tm*fibo)
             True
-            sage: Mfibo * Mtm == (fibo*tm)._matrix_()
+            sage: Mfibo * Mtm == matrix(fibo*tm)
             True
             sage: Mfibo.parent()
             Full MatrixSpace of 2 by 2 dense matrices over Integer Ring
@@ -551,12 +708,12 @@
         and column are given by the order defined on the alphabet of the
         domain and the codomain.
         
-        The matrix returned is over the integers. If a different ring is
-        desired, use either the change_ring function or the matrix
+        The matrix returned is over the integers.  If a different ring is
+        desired, use either the ``change_ring`` function or the ``matrix``
         function.
         
         EXAMPLES::
-        
+
             sage: m = WordMorphism('a->abc,b->a,c->c')
             sage: m.incidence_matrix()
             [1 1 0]
@@ -569,20 +726,22 @@
             [1 0 1 5 1]
         """
         L = []
-        for b in self.domain().alphabet():
-            w = self(b)
-            L.append(w.parikh_vector())
-
+        domain_alphabet = self.domain().alphabet()
+        codomain_alphabet = self.codomain().alphabet()
+        for b in domain_alphabet:
+            w = self._morph[b]
+            ev_dict = w.evaluation_dict()
+            L.append([ev_dict.get(a,0) for a in codomain_alphabet])
         M = Matrix(IntegerRing(), L).transpose()
         return M
 
         
     def domain(self):
         r"""
-        Returns domain of self.
+        Returns domain of ``self``.
         
         EXAMPLES::
-        
+
             sage: WordMorphism('a->ab,b->a').domain()
             Words over Ordered Alphabet ['a', 'b']
             sage: WordMorphism('b->ba,a->ab').domain()
@@ -594,10 +753,10 @@
         
     def codomain(self):
         r"""
-        Returns the domain of the images.
+        Returns the codomain of ``self``.
         
-        EXAMPLES ::
-        
+        EXAMPLES::
+
             sage: WordMorphism('a->ab,b->a').codomain()
             Words over Ordered Alphabet ['a', 'b']
             sage: WordMorphism('6->ab,y->5,0->asd').codomain()
@@ -607,10 +766,10 @@
         
     def is_endomorphism(self):
         r"""
-        Returns True if the codomain is a subset of the domain.
+        Returns ``True`` if the codomain is a subset of the domain.
         
-        EXAMPLES ::
-        
+        EXAMPLES::
+
             sage: WordMorphism('a->ab,b->a').is_endomorphism()
             True
             sage: WordMorphism('6->ab,y->5,0->asd').is_endomorphism()
@@ -627,10 +786,10 @@
     def images(self):
         r"""
         Returns the list of all the images of the letters of the alphabet
-        under self.
+        under ``self``.
         
-        EXAMPLES ::
-        
+        EXAMPLES::
+
             sage: WordMorphism('a->ab,b->a').images()
             [word: ab, word: a]
             sage: WordMorphism('6->ab,y->5,0->asd').images()
@@ -640,10 +799,10 @@
         
     def reversal(self):
         r"""
-        Returns the reversal of self.
+        Returns the reversal of ``self``.
         
-        EXAMPLES ::
-        
+        EXAMPLES::
+
             sage: print WordMorphism('6->ab,y->5,0->asd').reversal()
             WordMorphism: 0->dsa, 6->ba, y->5
             sage: print WordMorphism('a->ab,b->a').reversal()
@@ -653,11 +812,11 @@
         
     def is_empty(self):
         r"""
-        Returns True if the cardinality of the domain is zero and False
-        otherwise.
+        Returns ``True`` if the cardinality of the domain is zero and
+        ``False`` otherwise.
         
         EXAMPLES::
-        
+
             sage: WordMorphism('').is_empty()
             True
             sage: WordMorphism('a->a').is_empty()
@@ -667,11 +826,11 @@
         
     def is_erasing(self):
         r"""
-        Returns True if self is an erasing morphism, i.e. the image of a
+        Returns ``True`` if ``self`` is an erasing morphism, i.e. the image of a
         letter is the empty word.
         
-        EXAMPLES ::
-        
+        EXAMPLES::
+
             sage: WordMorphism('a->ab,b->a').is_erasing()
             False
             sage: WordMorphism('6->ab,y->5,0->asd').is_erasing()
@@ -682,16 +841,16 @@
             False
         """
         for image in self.images():
-            if len(image) == 0:
+            if image.is_empty():
                 return True
         return False
         
     def is_identity(self):
         r"""
-        Returns True if self is the identity morphism.
+        Returns ``True`` if ``self`` is the identity morphism.
         
         EXAMPLES::
-        
+
             sage: m = WordMorphism('a->a,b->b,c->c,d->e')
             sage: m.is_identity()
             False
@@ -715,40 +874,116 @@
             return False
             
         for letter in self.domain().alphabet():
-            if self(letter) != self.codomain()(letter):
+            img = self(letter)
+            if img.length() != 1:
+                return False
+            elif img[0] != letter:
                 return False
         return True
         
+    def partition_of_domain_alphabet(self):
+        r"""
+        Returns a partition of the domain alphabet.
+        
+        Let `\varphi:\Sigma^*\rightarrow\Sigma^*` be an involution. There
+        exists a triple of sets `(A, B, C)` such that 
+
+         -  `A \cup B \cup C =\Sigma`; 
+         -  `A`, `B` and `C` are mutually disjoint and
+         -  `\varphi(A)= B`, `\varphi(B)= A`, `\varphi(C)= C`.
+
+        These sets are not unique.
+        
+        INPUT:
+
+        - ``self`` - An involution.
+            
+        OUTPUT:
+
+        A tuple of three sets
+
+        EXAMPLES::
+
+            sage: m = WordMorphism('a->b,b->a')
+            sage: m.partition_of_domain_alphabet() #random ordering
+            ({'a'}, {'b'}, {})
+            sage: m = WordMorphism('a->b,b->a,c->c')
+            sage: m.partition_of_domain_alphabet() #random ordering
+            ({'a'}, {'b'}, {'c'})
+            sage: m = WordMorphism('a->a,b->b,c->c')
+            sage: m.partition_of_domain_alphabet() #random ordering
+            ({}, {}, {'a', 'c', 'b'})
+            sage: m = WordMorphism('A->T,T->A,C->G,G->C')
+            sage: m.partition_of_domain_alphabet() #random ordering
+            ({'A', 'C'}, {'T', 'G'}, {})
+            sage: I = WordMorphism({0:oo,oo:0,1:-1,-1:1,2:-2,-2:2,3:-3,-3:3})
+            sage: I.partition_of_domain_alphabet() #random ordering
+            ({0, -1, -3, -2}, {1, 2, 3, +Infinity}, {})
+
+        TESTS::
+
+            sage: m = WordMorphism('a->b,b->a,c->a')
+            sage: m.partition_of_domain_alphabet()
+            Traceback (most recent call last):
+            ...
+            TypeError: self is not an involution
+        """
+        if not self.is_involution():
+            raise TypeError, "self is not an involution"
+
+        A = set(); B = set(); C = set()
+        for a in self.domain().alphabet():
+            if a == self(a)[0]:
+                C.add(a)
+            elif not (a in A or a in B):
+                A.add(a)
+                B.add(self(a)[0]) 
+
+        return Set(A), Set(B), Set(C)
+
     def is_involution(self):
         r"""
-        Returns True if self is an involution, i.e. its square is the
-        identity.
+        Returns ``True`` if ``self`` is an involution, i.e. its square
+        is the identity.
+
+        INPUT:
+
+        - ``self`` - an endomorphism
         
         EXAMPLES::
-        
+
             sage: WordMorphism('a->b,b->a').is_involution()
             True
+            sage: WordMorphism('a->b,b->bb').is_involution()
+            False
+            sage: WordMorphism({0:[1],1:[0]}).is_involution()
+            True
+
+        TESTS::
+
             sage: WordMorphism('').is_involution()  
             True
-            sage: WordMorphism({0:[1],1:[0]}).is_involution()
-            True
+            sage: WordMorphism({0:1,1:0,2:3}).is_involution()
+            Traceback (most recent call last):
+            ...
+            TypeError: self (=WordMorphism: 0->1, 1->0, 2->3) is not a endomorphism
         """
+        if not self.is_endomorphism():
+            raise TypeError, "self (=%s) is not a endomorphism"%self
+
         return (self*self).is_identity()
         
     def _check_primitive(self):
         r"""
-        Returns True if all the letters of the domain appear in all the
+        Returns ``True`` if all the letters of the domain appear in all the 
         images of letters of the domain.
-        
+
         INPUT:
-        
-        
-        -  ``self`` - the codomain must be an instance of
-           Words
-        
-        
+
+        - ``self`` - the codomain must be an instance of Words
+
         EXAMPLES::
-        
+
             sage: m = WordMorphism('a->ab,b->ba')
             sage: m._check_primitive()
             True
@@ -759,40 +994,33 @@
             WordMorphism: 2->456, 3->418
             sage: WordMorphism({2:[4,5,6],3:[4,1,8]})._check_primitive()
             False
+
         """
-        if not is_Words(self.codomain()):
+        if not isinstance(self.codomain(),Words_all):
             raise TypeError, "codomain of self(=%s) must be an instance of Words"%self
 
-        dom_alphabet = self.domain().alphabet()
+        dom_alphabet = set(self.domain().alphabet())
 
         for image in self.images():
-            if not dom_alphabet <= OrderedAlphabet(set(image)):
+            if not dom_alphabet <= set(image):
                 return False 
         else:
             return True
 
     def is_primitive(self):
         r"""
-        Returns True if self is primitive.
+        Returns ``True`` if ``self`` is primitive.
         
+        A morphism `\varphi` is *primitive* if there exists 
+        an positive integer `k` such that for all `\alpha\in\Sigma`,
+        `\varphi^k(\alpha)` contains all the letters of `\Sigma`.
+
         INPUT:
-        
-        
-        -  ``self`` - an endomorphism
-        
-        
-        -In English: A morphism `\varphi` is *primitive* if there
-        exists an positive integer `k` such that for all
-        `\alpha\in\Sigma`, `\varphi^k(\alpha)` contains all
-        the letters of `\Sigma`.
-        
-        -En français: Un morphisme `\varphi` est *primitif* s'il
-        existe un nombre naturel `k` tel que pour tout
-        `\alpha\in\Sigma, \varphi^k(\alpha)` contient toutes les
-        lettres de `\Sigma`.
+
+        - ``self`` - an endomorphism
         
         EXAMPLES::
-        
+
             sage: tm = WordMorphism('a->ab,b->ba')
             sage: tm.is_primitive()
             True
@@ -805,6 +1033,9 @@
             sage: f = WordMorphism({0:[1],1:[0]})
             sage: f.is_primitive()
             False
+
+        TESTS::
+
             sage: m = WordMorphism('a->bb,b->aac')
             sage: m.is_primitive()
             Traceback (most recent call last):
@@ -833,28 +1064,22 @@
         
     def is_prolongable(self, letter):
         r"""
-        Returns True if self is prolongable on letter.
+        Returns ``True`` if ``self`` is prolongable on ``letter``.
         
-        A morphism `\varphi` is prolongable on a letter `a`
+        A morphism `\varphi` is prolongable on a letter `a` 
         if `a` is a prefix of `\varphi(a)`.
         
         INPUT:
-        
-        
-        -  ``self`` - the codomain must be an instance of
-           Words
-        
-        -  ``letter`` - in the domain alphabet
-        
-        
+
+        - ``self`` - its codomain must be an instance of Words
+        - ``letter`` - a letter in the domain alphabet
+            
         OUTPUT:
-        
-        
-        -  ``boolean`` - if self is prolongable on letter.
-        
-        
+
+        Boolean
+            
         EXAMPLES::
-        
+
             sage: WordMorphism('a->ab,b->a').is_prolongable(letter='a')
             True
             sage: WordMorphism('a->ab,b->a').is_prolongable(letter='b')
@@ -867,13 +1092,16 @@
             False
             sage: WordMorphism('a->bb,b->aac').is_prolongable(letter='a')
             False
-        
+                                    
         TESTS::
-        
+
             sage: WordMorphism('a->ab,b->b,c->ba').is_prolongable(letter='d')
             Traceback (most recent call last):
             ...
             TypeError: letter (=d) is not in the domain alphabet (=Ordered Alphabet ['a', 'b', 'c'])
+
+        ::
+
             sage: n0, n1 = matrix(2,[1,1,1,0]), matrix(2,[2,1,1,0])
             sage: n = {'a':n0, 'b':n1}
             sage: WordMorphism(n).is_prolongable(letter='a') #todo: not implemented
@@ -881,7 +1109,7 @@
             ...
             TypeError: codomain of self must be an instance of Words
         """
-        if not is_Words(self.codomain()):
+        if not isinstance(self.codomain(),Words_all):
             raise TypeError, "codomain of self must be an instance of Words"
 
 
@@ -893,29 +1121,25 @@
         
     def letter_iterator(self, letter):
         r"""
-        Returns an iterator of the letters of the fixed point of self
-        starting with letter.
-        
-        If w is the word, then this iterator: outputs the elements of
-        morphism[ w[i] ], appends morphism[ w[i+1] ] to w, increments i.
-        
+        Returns an iterator of the letters of the fixed point of ``self``
+        starting with ``letter``.
+
+        If w is the iterated word, then this iterator: outputs the elements 
+        of morphism[ w[i] ], appends morphism[ w[i+1] ] to w, increments i.
+            
         INPUT:
-        
-        
-        -  ``self`` - an endomorphism, must be prolongable on
+
+        -  ``self`` - an endomorphism, must be prolongable on 
            letter
-        
-        -  ``letter`` - in the domain of self
-        
-        
+
+        -  ``letter`` - a letter in the domain of ``self``
+       
         OUTPUT:
-        
-        
+
         -  ``iterator`` - iterator of the fixed point
         
-        
         EXAMPLES::
-        
+
             sage: m = WordMorphism('a->abc,b->,c->')
             sage: list(m.letter_iterator('b'))
             Traceback (most recent call last):
@@ -935,90 +1159,76 @@
         if not self.is_prolongable(letter=letter):
             raise TypeError, "self must be prolongable on %s"%letter
         
-        w = self(letter)
-        i = 0
-        while w:
-            for a in self(w[i]):
+        w = list(self(letter))
+        while True:
+            for a in self(w.pop(0)):
                 yield a
             else:
-                i += 1
-                if i >= len(w):
+                if w:
+                    w.extend(self(w[0]))
+                else:
                     raise StopIteration
-                else:
-                    w *= self(w[i])
-
-        ## This appears to be slower than the above, and I'm not sure why.
-        #while w:
-        #    for a in self[w.pop(0)]:
-        #        yield a
-        #    w += self[w[0]]
         
     def fixed_point(self, letter):
         r"""
-        Returns the fixed point of self beginning by the given letter.
-        
-        A fixed point of morphism `\varphi` is a word `w`
-        such that `\varphi(w) = w`.
-        
+        Returns the fixed point of ``self`` beginning by the given ``letter``.
+
+        A fixed point of morphism `\varphi` is a word `w` such that 
+        `\varphi(w) = w`.
+
         INPUT:
-        
-        
-        -  ``self`` - an endomorphism, must be prolongable on
-           letter
-        
-        -  ``letter`` - in the domain of self, the first letter
+
+        -  ``self`` - an endomorphism, must be prolongable on ``letter``
+
+        -  ``letter`` - in the domain of ``self``, the first letter 
            of the fixed point.
-        
-        
+                             
         OUTPUT:
-        
-        
-        -  ``word`` - the fixed point of self beginning with
-           letter.
-        
-        
+
+        - ``word`` - the fixed point of ``self`` beginning with ``letter``.
+                   
         EXAMPLES:
         
         1. Infinite fixed point::
-        
-            sage: WordMorphism('a->ab,b->ba').fixed_point(letter='a')                        
+
+            sage: WordMorphism('a->ab,b->ba').fixed_point(letter='a')
             Fixed point beginning with 'a' of the morphism WordMorphism: a->ab, b->ba
             sage: WordMorphism('a->ab,b->a').fixed_point(letter='a') 
             Fixed point beginning with 'a' of the morphism WordMorphism: a->ab, b->a
             sage: WordMorphism('a->ab,b->b,c->ba').fixed_point(letter='a')
             Fixed point beginning with 'a' of the morphism WordMorphism: a->ab, b->b, c->ba
-        
+
         2. Infinite fixed point of an erasing morphism::
-        
+
             sage: WordMorphism('a->ab,b->,c->ba').fixed_point(letter='a') 
             Fixed point beginning with 'a' of the morphism WordMorphism: a->ab, b->, c->ba
-        
+            
         3. Finite fixed point::
-        
+
             sage: WordMorphism('a->ab,b->b,c->ba').fixed_point(letter='b')
             word: b
-        
+            
         4. Finite fixed point of an erasing morphism::
-        
+
             sage: m = WordMorphism('a->abc,b->,c->')
             sage: fp = m.fixed_point('a'); fp
             Fixed point beginning with 'a' of the morphism WordMorphism: a->abc, b->, c->
             sage: fp[:10]
             word: abc
-            sage: m = WordMorphism('a->ba,b->')                                                       
+            sage: m = WordMorphism('a->ba,b->')
             sage: m('ba') 
             word: ba
             sage: m.fixed_point('a') #todo: not implemented
             word: ba
-        
+            
         5. Fixed point of a power of a morphism::
-        
+
             sage: m = WordMorphism('a->ba,b->ab')
             sage: (m^2).fixed_point(letter='a')
             Fixed point beginning with 'a' of the morphism WordMorphism: a->abba, b->baab
-        
+            
         TESTS::
-        
+
             sage: WordMorphism('a->ab,b->,c->ba').fixed_point(letter='b') 
             Traceback (most recent call last):
             ...
@@ -1044,21 +1254,19 @@
 
         image = self(letter)
 
-        if len(image) == 1:
+        if image.length() == 1:
             return image
             
         # Construct the word.
-        w = self.codomain()(self.letter_iterator(letter), format='iterator')
+        w = self.codomain()(self.letter_iterator(letter), datatype='iter')
         w.rename("Fixed point beginning with %r of the morphism %s"%(letter,self))
         return w
 
     def list_fixed_points(self):
         r"""
-        Returns the list of all fixed points of self.
-        
-        EXAMPLES
-        
-        ::
+        Returns the list of all fixed points of ``self``.
+
+        EXAMPLES::
         
             sage: WordMorphism('a->ab,b->ba').list_fixed_points() #not implemented
             [Fixed point beginning with 'a' of the morphism WordMorphism: a->ab, b->ba,
@@ -1068,14 +1276,15 @@
         
     def conjugate(self, pos):
         r"""
-        Returns the morphism where each image of self is conjugate of
-        parameter pos.
+        Returns the morphism where the image of the letter by ``self`` 
+        is conjugated of parameter ``pos``.
+
+        INPUT:
+
+        - ``pos`` - integer
         
-        Retourne le morphisme dont toutes les images ont etes conjuguees de
-        pos.
-        
-        EXAMPLES ::
-        
+        EXAMPLES::
+
             sage: m = WordMorphism('a->abcde')
             sage: m.conjugate(0) == m
             True
@@ -1093,14 +1302,11 @@
         
     def has_left_conjugate(self):
         r"""     
-        Returns true if all the non empty images of self begins with the
-        same letter.
-        
-        Retourne vrai si toutes les images non vides commencent par la meme
-        lettre.
+        Returns ``True`` if all the non empty images of ``self`` begins with 
+        the same letter.
         
         EXAMPLES::
-        
+
             sage: m = WordMorphism('a->abcde,b->xyz')
             sage: m.has_left_conjugate()
             False
@@ -1115,7 +1321,7 @@
             sage: WordMorphism('a->abbab,b->abb,c->').has_left_conjugate()    
             True
         """
-        I = ifilterfalse(FiniteWord_over_OrderedAlphabet.is_empty, self.images())
+        I = ifilterfalse(FiniteWord_class.is_empty, self.images())
         
         try:
             letter = I.next()[0]
@@ -1131,14 +1337,11 @@
         
     def has_right_conjugate(self):
         r"""     
-        Returns true if all the non empty images of self ends with the same
-        letter.
-        
-        Retourne vrai si toutes les images non vide terminent par la meme
-        lettre.
+        Returns ``True`` if all the non empty images of ``self`` ends with the 
+        same letter.
         
         EXAMPLES::
-        
+
             sage: m = WordMorphism('a->abcde,b->xyz')
             sage: m.has_right_conjugate()
             False
@@ -1157,26 +1360,22 @@
         
     def list_of_conjugates(self):
         r"""     
-        Retourne une liste des morphismes conjugues du receveur obtenus en
-        conjuguant les prefixes (et suffixes) communs de chacune des
-        images.
+        Returns the list of all the conjugate morphisms of ``self``.
+
+        DEFINITION: 
         
-        Returns the list of all the conjugate morphisms of self obtain by
-        taking the conjugate of the common prefixes and suffixes of all the
-        images.
-        
-        DEFINITION (from [1]): Recall from Lothaire [2] (Section 2.3.4)
+        Recall from Lothaire [1] (Section 2.3.4)
         that `\varphi` is *right conjugate* of `\varphi'`,
         noted `\varphi\triangleleft\varphi'`, if there exists
         `u \in \Sigma^*` such that
         
         .. math::
         
-            \varphi(\alpha)u = u\varphi'(\alpha), \quad \textrm{for all } \alpha \in \Sigma
-        
-        ,
-        or equivalently that `\varphi(x)u = u\varphi'(x)`, for all
-        words `x \in \Sigma^*`. Clearly, this relation is not
+            \varphi(\alpha)u = u\varphi'(\alpha), 
+            
+        for all `\alpha \in \Sigma`, or equivalently that 
+        `\varphi(x)u = u\varphi'(x)`, for all words `x \in \Sigma^*`.
+        Clearly, this relation is not
         symmetric so that we say that two morphisms `\varphi` and
         `\varphi'` are *conjugate*, noted
         `\varphi\bowtie\varphi'`, if
@@ -1186,14 +1385,11 @@
         
         REFERENCES:
 
-        - [1] A. Blondin-Massé, S. Brlek, S. Labbé, Palindromic
-          lacunas of the Thue-Morse word, 2008, to appear.
-
-        - [2] M. Lothaire, Algebraic Combinatorics on words, Cambridge
+        - [1] M. Lothaire, Algebraic Combinatorics on words, Cambridge
           University Press, 2002.
         
         EXAMPLES::
-        
+
             sage: m = WordMorphism('a->abbab,b->abb')
             sage: map(str, m.list_of_conjugates())
             ['WordMorphism: a->babba, b->bab',
@@ -1251,58 +1447,43 @@
 
     def is_in_classP(self, f=None):
         r"""   
-        Returns True if self is in class `P` (or
-        `f`-`P`).
+        Returns ``True`` if ``self`` is in class `P` (or `f`-`P`).
         
-        DEFINITION: "[Let `A` be an alphabet] We say that a
+        DEFINITION : Let `A` be an alphabet. We say that a
         primitive substitution `S` is in the *class P* if there
         exists a palindrome `p` and for each `b\in A` a
         palindrome `q_b` such that `S(b)=pq_b` for all
-        `b\in A`." [1]
+        `b\in A`. [1] 
         
-        Let `\Sigma` be an alphabet and `f` be an
-        involution on `\Sigma`. "We say that a morphism
-        `\varphi` is in class `f`-P if there exists an
-        `f`-palindrome
-        `p\in\hbox{f - \rm Pal}(\Sigma^*)` and for each
-        `\alpha \in \Sigma` there exists an `f`-palindrome
-        `q_\alpha\in\hbox{f - \rm Pal}(\Sigma^*)` such
-        that `\varphi(\alpha)=pq_\alpha`." [2]
+        Let `f` be an involution on `A`. "We say that a morphism
+        `\varphi` is in class `f`-`P` if there exists an
+        `f`-palindrome `p` and for each `\alpha \in A` 
+        there exists an `f`-palindrome `q_\alpha` such
+        that `\varphi(\alpha)=pq_\alpha`. [2]
         
         INPUT:
-        
-        
-        -  ``f`` - involution (default: None) on the alphabet
-           of self. It must be something that WordMorphism's contructor
-           understand (dict, str, ...).
-        
-        
-        OUTPUT:
-        
-        
-        -  ``boolean`` - True if f is None and if self is in
-           class P; True otherwise and if self is in class `f`-P;
-           False otherwise.
-        
-        
+
+        -  ``f`` - involution (default: None) on the alphabet of ``self``. 
+           It must be callable on letters as well as words (e.g. WordMorphism).
+                             
         REFERENCES:
 
         - [1] Hof, A., O. Knill et B. Simon, Singular continuous
           spectrum for palindromic Schrödinger operators,
           Commun. Math. Phys.  174 (1995) 149-159.
 
-        - [2] Labbé, Sébastien. Propriétés combinatoires des
-          `f`-palindromes, Mémoire de maîtrise en Mathématiques,
-          Montréal, UQAM, 2008, 109 pages.
+        - [2] Labbe, Sebastien. Proprietes combinatoires des
+          `f`-palindromes, Memoire de maitrise en Mathematiques,
+          Montreal, UQAM, 2008, 109 pages.
         
         EXAMPLES::
-        
+
             sage: WordMorphism('a->bbaba,b->bba').is_in_classP()
             True
             sage: tm = WordMorphism('a->ab,b->ba')
             sage: tm.is_in_classP()
             False
-            sage: f='a->b,b->a'
+            sage: f = WordMorphism('a->b,b->a')
             sage: tm.is_in_classP(f=f)
             True
             sage: (tm^2).is_in_classP()
@@ -1316,8 +1497,8 @@
             False
             sage: (fibo^2).is_in_classP()
             False
-            sage: f='a->b,b->a,c->c'
-            sage: WordMorphism('a->acbcc,b->acbab,c->acbba').is_in_classP (f)
+            sage: f = WordMorphism('a->b,b->a,c->c')
+            sage: WordMorphism('a->acbcc,b->acbab,c->acbba').is_in_classP(f)
             True
         """
         if self.is_empty():
@@ -1330,7 +1511,7 @@
             lcp = lcp.longest_common_prefix(image)
         
         #Find a common palindrome prefix
-        for i in range(len(lcp)+1):
+        for i in range(lcp.length()+1):
             if lcp[:i].is_palindrome(f=f):
                 
                 #If all the suffixes are palindromes,
@@ -1344,51 +1525,37 @@
         
     def has_conjugate_in_classP(self, f=None):
         r"""   
-        Returns True if self has a conjugate in class
-        `f`-`P`.
+        Returns ``True`` if ``self`` has a conjugate in class `f`-`P`.
         
-        DEFINITION: Let `\Sigma` be an alphabet and `f` be
-        an involution on `\Sigma`. "We say that a morphism
-        `\varphi` is in class `f`-P if there exists an
-        `f`-palindrome
-        `p\in\hbox{f - \rm Pal}(\Sigma^*)` and for each
-        `\alpha \in \Sigma` there exists an `f`-palindrome
-        `q_\alpha\in\hbox{f - \rm Pal}(\Sigma^*)` such
-        that `\varphi(\alpha)=pq_\alpha`." [2]
+        DEFINITION : Let `A` be an alphabet. We say that a
+        primitive substitution `S` is in the *class P* if there
+        exists a palindrome `p` and for each `b\in A` a
+        palindrome `q_b` such that `S(b)=pq_b` for all
+        `b\in A`. [1] 
         
-        We say that a morphism `\varphi'` est de classe
-        `f-P'` if there exists a morphism `\varphi`
-        conjugate of `\varphi'` such that `\varphi` is in
-        class `f`-P. [2]
+        Let `f` be an involution on `A`. We say that a morphism
+        `\varphi` is in class `f`-`P` if there exists an
+        `f`-palindrome `p` and for each `\alpha \in A` 
+        there exists an `f`-palindrome `q_\alpha` such
+        that `\varphi(\alpha)=pq_\alpha`. [2]
         
         INPUT:
-        
-        
-        -  ``f`` - involution (default: None) on the alphabet
-           of self. It must be something that WordMorphism's contructor
-           understand (dict, str, ...).
-        
-        
-        OUTPUT:
-        
-        
-        -  ``boolean`` - True if f is None and if self has a
-           conjugate in class P; True otherwise and if self has a conjugate in
-           class `f`-P; False otherwise.
-        
-        
+
+        -  ``f`` - involution (default: None) on the alphabet of ``self``. 
+           It must be callable on letters as well as words (e.g. WordMorphism).
+                             
         REFERENCES:
 
         - [1] Hof, A., O. Knill et B. Simon, Singular continuous
           spectrum for palindromic Schrödinger operators,
           Commun. Math. Phys.  174 (1995) 149-159.
 
-        - [2] Labbé, Sébastien. Propriétés combinatoires des
-          `f`-palindromes, Mémoire de maîtrise en Mathématiques,
-          Montréal, UQAM, 2008, 109 pages.
+        - [2] Labbe, Sebastien. Proprietes combinatoires des
+          `f`-palindromes, Memoire de maitrise en Mathematiques,
+          Montreal, UQAM, 2008, 109 pages.
         
         EXAMPLES::
-        
+
             sage: fibo = WordMorphism('a->ab,b->a')
             sage: fibo.has_conjugate_in_classP()           
             True
@@ -1402,41 +1569,3 @@
                 return True
         return False
 
-#    def _latex_(self):
-#        r"""        
-#        Returns latex representation of this morphism.
-#        
-#        EXAMPLES:
-#            sage: tm = WordMorphism('a->ab,b->ba'); print tm._latex_()
-#            \begin{array}{cccl}
-#            \varphi: & [\text{a}, \text{b}]^* \cup [\text{a}, \text{b}]^\omega & \rightarrow & [\text{a}, \text{b}]^* \cup [\text{a}, \text{b}]^\omega \\
-#            & \text{a} & \mapsto & \text{ab} \\
-#            & \text{b} & \mapsto & \text{ba}
-#            \end{array}
-#            sage: fibo = WordMorphism('a->ab,b->a'); print (fibo^3)._latex_()
-#            \begin{array}{cccl}
-#            \varphi: & [\text{a}, \text{b}]^* \cup [\text{a}, \text{b}]^\omega & \rightarrow & [\text{a}, \text{b}]^* \cup [\text{a}, \text{b}]^\omega \\
-#            & \text{a} & \mapsto & \text{abaab} \\
-#            & \text{b} & \mapsto & \text{aba}
-#            \end{array}
-#            sage: print (WordMorphism(''))._latex_()
-#            \begin{array}{cccl}
-#            \varphi: & []^* \cup []^\omega & \rightarrow & []^* \cup []^\omega
-#            \end{array}
-#            sage: print (WordMorphism('b->baa,a->ab'))._latex_()
-#            \begin{array}{cccl}
-#            \varphi: & [\text{a}, \text{b}]^* \cup [\text{a}, \text{b}]^\omega & \rightarrow & [\text{a}, \text{b}]^* \cup [\text{a}, \text{b}]^\omega \\
-#            & \text{a} & \mapsto & \text{ab} \\
-#            & \text{b} & \mapsto & \text{baa}
-#            \end{array}
-#        """
-#        dom = self.domain()
-#        cod = self.codomain()
-#        
-#        lines = ["\\varphi: & %s & \\rightarrow & %s" %(latex(dom), latex(cod))]
-#        lines += ['& %s & \mapsto & %s' %(latex(b), latex(self(b).string_rep()))  for b in dom.alphabet()]
-#        s = " \\\\\n".join(lines)
-#
-#        return "\\begin{array}{cccl}\n" + s + "\n\\end{array}"
-        
-        
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/words/notes/historic.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sage/combinat/words/notes/historic.txt	Fri Jul 17 23:25:52 2009 +0200
@@ -0,0 +1,47 @@
+====================================================
+An historic of the Words Library
+====================================================
+
+[English historic to be done. To be translated from below.]
+
+
+
+
+====================================================
+Historique de la librairie sur les mots
+====================================================
+
+Depuis 1990, Srecko Brlek détient une subvention du CRSNG, pour des recherches théoriques dont le coeur est la combinatoire des mots et un de ses  volets concerne le développement d'un outil de calcul formel pour la combinatoire des mots.
+
+Le paquetage disponible ici doit beaucoup au travail de plusieurs personnes. À l'origine Patricia Lamas a construit pendant ses études de maitrise (1995) sous la direction de Srečko Brlek, un ensemble de fonctions en langage Scheme pour la manipulation de mots.
+
+En 1996, lors d'un workshop organisé à Montréal par Srecko Brlek ( Valérie Berthé, Julien Cassaigne, Sebastien Ferenczi, Michel Koskas, Dominique Bernardi, Jean Paul Allouche, etc) une discussion portyant sur le développement a mené à la volonté de poursuivre le projet nommé CABAC. Cela n'a pas abouti... complètement comme nous allons le voir.
+
+En 1997, Annie Ladouceur, pendant un stage à Paris de janvier à juin, a
+complètement réécrit en C une librairie de fonctions pour la
+combinatoire des mots. Elle a su bénéficier, dans le cadre de ce stage,
+du support de Dominique Bernardi, Michel Koskas et Jean-Paul Allouche.
+Ce travail constituait une grande partie de son mémoire de maitrise
+(1999) effectué sous la direction de Srečko Brlek et lui a permis en
+outre de découvrir le canard à la ficelle. De plus, la possibilité
+d'effectuer des calculs sur des mots très longs (plusieurs dizaines de
+millions de caractères), a donné lieu à quelques découvertes et entrainé
+la publication de 2 articles portant sur le mot de Kolakoski. La
+maintenance de cet outil étant ardue, Xavier Provençal, doctorant sous
+la direction toujours de l'hidalgo de Novosibirsk, a repris le travail
+de Annie en 2003. 
+
+En 2006, une  version  complète en ruby, fut produite par Arnaud Bergeron, boursier CRSNG, pendant son stage d'initiation à la recherche effectué au LaCIM à l'été 2006, sous la direction de Srečko Brlek. Thierry Montheil (Lirmm) a aussi manifesté de l'intérêt pour son développement. 
+
+Elle a permis de corriger plusieurs bugs.  Ce paquetage comportait des lacunes, principalement en ce qui a trait a l'interface.  Le manque de convivialité etait aussi un blocage a son utilisation.  
+
+En mai 2008, Franco Saliola nous a introduit à Sage lors d'un seminaire.  A la suite de ce seminaire il fut decide (Srecko Brlek, Franco Saliola, Arnaud Bergeron, Sebastien Labbé) que il serait opportun de porter le travail de Arnaud Bergeron sur la plateforme SAGE. Arnaud n'etait pas convaincu au debut de la chose, principalement a cause du langage de developpement Python. L'influence de Franco et de Sebastien sur Arnaud fur preponderante parce qu'il n'ecoute pas  so parrain. 
+
+Sebastien a pu lui montrer les beautes de Python, car il a developpe en langage Python independemment dans le cadre de sa maitrise un ensemble de fonctions usuelles pour la combinatoire des mots utiles pour son mémoire.
+
+Un cours sur SAGE fut donné au LaCIM par Franco Saliola  pendant deux semaines, à la suite duquel Arnaud a traduit en Python le paquetage Ruby, porté le résultat dans l'environnement SAGE, aidé en cela par Sébastien Labbé et Franco Saliola qui en est le maitre d'oeuvre.  D'autres contributions furent ajoutées par Amy Glen, postdoctorante au LaCIM. 
+
+Références :
+Laboratoire de Combinatoire Informatique Mathématiques (LaCIM) de l'Université du Québec à Montréal (UQAM), http://lacim.uqam.ca.
+
+
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/words/notes/new_structure.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sage/combinat/words/notes/new_structure.txt	Fri Jul 17 23:25:52 2009 +0200
@@ -0,0 +1,33 @@
+IDEA: A word will inherit from exactly one class from each of the two lists
+below.
+
+(A) CLASSES THAT CONTAIN METHODS ONLY. These classes will contain generic
+    implementations of many of the algorithms. 
+
+    Word_class
+    FiniteWord_class
+    InfiniteWord_class
+    Word_over_Alphabet_class
+    Word_over_OrderedAlphabet_class
+
+We will write the generic methods for any iterable object.
+
+(B) CLASSES FOR SPECIFIC IMPLEMENTATIONS. These will possibly override some
+    of the above methods.
+
+    Word_list
+    Word_string
+    Word_tuple
+    Word_iterator
+    Word_function
+    Word_iterator_cached
+    Word_function_cached
+
+At the very least, these need to define an iterator. But it would be better
+to implement the following:
+
+    __iter__, an iterator iterating through the letters
+    __getitem__, handle indexes and slices
+    __contains__, answer whether a letter is in the word
+    __len__, return the length of the word
+    [TODO: ADD TO THIS LIST]
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/words/notes/word_inheritance_howto.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sage/combinat/words/notes/word_inheritance_howto.txt	Fri Jul 17 23:25:52 2009 +0200
@@ -0,0 +1,60 @@
+# coding=utf-8
+#*****************************************************************************
+#       Copyright (C) 2009 Franco Saliola <saliola@gmail.com>
+#
+#  Distributed under the terms of the GNU General Public License version 2 (GPLv2)
+#
+#  The full text of the GPLv2 is available at:
+#
+#                  http://www.gnu.org/licenses/
+#*****************************************************************************
+
+To define a new class of words, one should inherit from Words_all (or any
+class that inherits from it) and implement the following methods.
+
+    - self.alphabet() -- return the alphabet (by default, self._alphabet)
+
+    - size_of_alphabet -- number of letters in the underlying alphabet (can
+      by Infinity)
+
+    - cmp_letters(x,y) -- a function to compare letters in the alphabet;
+      should behave like Python's cmp function (that is, it returns -1, 0
+      or 1, if x < y, x == y, x > y, respectively). By default, this points
+      to Python's cmp function.
+
+    - has_letter(x) -- returns True or False according to whether the
+      alphabet contains x or not. Default implementation: x in self._alphabet.
+
+By implementing the above methods, almost anything can be used as an
+alphabet. 
+
+EXAMPLE 1: Using a list for the alphabet.
+
+    self._alphabet = [0,1,2,3]
+
+    def size_of_alphabet(self):
+        return len(self._alphabet)
+
+    def cmp_letters(self,x,y):
+        return cmp(self._alphabet.index(x), self._alphabet.index(y))
+
+EXAMPLE 2: Using a CombinatorialClass as an alphabet.
+
+    self._alphabet = Partitions(3)
+
+    def size_of_alphabet(self):
+        return self._alphabet.cardinality()
+
+    def cmp_letters(self, letter1, letter2):
+        return self._alphabet.rank(letter1) - self._alphabet.rank(letter2)
+
+EXAMPLE 3: Integers.
+
+    self._alphabet = ZZ
+
+    def size_of_alphabet(self):
+        return Infinity
+
+    def cmp_letters(self, letter1, letter2):
+        return letter1 - letter2
+
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/words/shuffle_product.py
--- a/sage/combinat/words/shuffle_product.py	Thu Jul 09 15:14:36 2009 -0700
+++ b/sage/combinat/words/shuffle_product.py	Fri Jul 17 23:25:52 2009 +0200
@@ -1,5 +1,5 @@
-"""
-Shuffle products
+r"""
+Shuffle product of words
 """
 #*****************************************************************************
 #       Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>, 
@@ -16,19 +16,17 @@
 #
 #                  http://www.gnu.org/licenses/
 #*****************************************************************************
-from sage.combinat.words.word import is_Word
-from sage.combinat.words.word_content import BuildWordContent
+from sage.combinat.words.word import Word_class
 from sage.combinat.combinat import CombinatorialClass
 from sage.rings.all import binomial
 from sage.combinat.integer_vector import IntegerVectors
 from sage.combinat.subset import Subsets
-import copy
 
 class ShuffleProduct_w1w2(CombinatorialClass):
     def __init__(self, w1, w2):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2
             sage: W = Words([1,2,3,4])
             sage: s = ShuffleProduct_w1w2(W([1,2]),W([3,4]))
@@ -41,7 +39,7 @@
     def __repr__(self):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2
             sage: W = Words("abcd")
             sage: repr(ShuffleProduct_w1w2(W("ab"),W("cd")))
@@ -52,7 +50,7 @@
     def __contains__(self, x):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2
             sage: W = Words("abcd")
             sage: w = W("ab")
@@ -65,13 +63,13 @@
             sage: w in S
             False
         """
-        if not is_Word(x):
+        if not isinstance(x, Word_class):
             return False
-        if len(x) != len(self._w1) + len(self._w2):
+        if x.length() !=self._w1.length() + self._w2.length():
             return False
-        w1 = list(self._w1._word_content)
-        w2 = list(self._w2._word_content)
-        wx = list(x._word_content)
+        w1 = list(self._w1)
+        w2 = list(self._w2)
+        wx = list(x)
         for _ in range(len(wx)):
             try:
                 letter = wx.pop(0)
@@ -87,24 +85,25 @@
         
     def cardinality(self):
         """
-         Returns the number of words in the shuffle product of w1 and w2.
-         
-         It is given by binomial(len(w1)+len(w2), len(w1)).
-         
-         EXAMPLES::
-         
-             sage: from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2
-             sage: w, u = map(Words("abcd"), ["ab", "cd"])
-             sage: S = ShuffleProduct_w1w2(w,u)
-             sage: S.cardinality()
-             6
+        Returns the number of words in the shuffle product
+        of w1 and w2.
+
+        It is given by binomial(len(w1)+len(w2), len(w1)).
+
+        EXAMPLES::
+
+            sage: from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2
+            sage: w, u = map(Words("abcd"), ["ab", "cd"])
+            sage: S = ShuffleProduct_w1w2(w,u)
+            sage: S.cardinality()
+            6
          """
-        return binomial(len(self._w1)+len(self._w2), len(self._w1))
+        return binomial(self._w1.length()+self._w2.length(), self._w1.length())
 
     def _proc(self, vect):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2
             sage: w, u = map(Words("abcd"), ["ab", "cd"])
             sage: S = ShuffleProduct_w1w2(w,u)
@@ -127,11 +126,11 @@
 
     def __iter__(self):
         """
-        Returns an iterator for the words in the shuffle product of w1 and
-        w2.
-        
+        Returns an iterator for the words in the
+        shuffle product of w1 and w2.
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2
             sage: w, u = map(Words("abcd"), ["ab", "cd"])
             sage: S = ShuffleProduct_w1w2(w,u)
@@ -147,32 +146,33 @@
     def __init__(self, w1, w2):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.shuffle_product import ShuffleProduct_shifted
-            sage: w, u = map(Words("abcdef"), ["ab", "cd"])
+            sage: w, u = Word([1,2]), Word([3,4])
             sage: S = ShuffleProduct_shifted(w,u)
             sage: S == loads(dumps(S))
             True
         """
-        w2c = BuildWordContent([x + len(w1) for x in w2._word_content])
-        ShuffleProduct_w1w2.__init__(self, w1, w1.parent()(w2c))
+        shift = w1.length()
+        shifted_w2 = w1.parent()([x + shift for x in w2])
+        ShuffleProduct_w1w2.__init__(self, w1, shifted_w2)
 
     def __repr__(self):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.shuffle_product import ShuffleProduct_shifted
-            sage: w, u = map(Words("abcdef"), ["ab", "cd"])
+            sage: w, u = Word([0,1]), Word([2,3])
             sage: ShuffleProduct_shifted(w,u).__repr__()
-            'Shifted shuffle product of word: ab and word: ef'
+            'Shuffle product of word: 01 and word: 45'
         """
-        return "Shifted shuffle product of %s and %s"%(self._w1, self._w2)
+        return "Shuffle product of %s and %s"%(self._w1, self._w2)
 
 class ShuffleProduct_overlapping_r(CombinatorialClass):
     def __init__(self, w1, w2, r):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.shuffle_product import ShuffleProduct_overlapping_r
             sage: w, u = map(Words("abcdef"), ["ab", "cd"])
             sage: S = ShuffleProduct_overlapping_r(w,u,1)
@@ -186,7 +186,7 @@
     def __repr__(self):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.shuffle_product import ShuffleProduct_overlapping_r
             sage: w, u = map(Words("abcdef"), ["ab", "cd"])
             sage: ShuffleProduct_overlapping_r(w,u,1).__repr__()
@@ -197,28 +197,28 @@
     def __iter__(self):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.shuffle_product import ShuffleProduct_overlapping_r
-            sage: w, u = map(Words("abcdef"), ["ab", "cd"])
-            sage: ShuffleProduct_overlapping_r(w,u,1).list() #indirect doctest
-            [word: dbd, word: aed, word: ddb, word: acf, word: ceb, word: caf]
+            sage: w, u = Word([1,2]), Word([3,4])
+            sage: ShuffleProduct_overlapping_r(w,u,1).list()
+            [word: 424, word: 154, word: 442, word: 136, word: 352, word: 316]
             sage: w, u = map(Words(range(1,7)), [[1,2], [3,4]])
+            sage: W = Words(range(1,7))
+            sage: w, u = W([1,2]), W([3,4])
             sage: ShuffleProduct_overlapping_r(w, u, 1).list() #indirect doctest
             [word: 424, word: 154, word: 442, word: 136, word: 352, word: 316]
         """
         W = self._w1.parent()
-        alphabet = W.alphabet()
 
         m = len(self._w1)
         n = len(self._w2)
         r = self.r
 
-        wc1 = [i+1 for i in self._w1._word_content]
-        wc2 = [i+1 for i in self._w2._word_content]
+        wc1, wc2 = self._w1, self._w2
         
         blank = [0]*(m+n-r)
         for iv in IntegerVectors(m, m+n-r, max_part=1):
-            w = copy.copy(blank)
+            w = blank[:]
             filled_places = []
             unfilled_places = []
             #Fill in w1 into the iv slots
@@ -238,18 +238,18 @@
 
                 #Fill in w2 into the places
                 i = 0
-                res = copy.copy(w)
+                res = w[:]
                 for j in places_to_fill:
                     res[j] += wc2[i]
                     i += 1
 
-                yield W(BuildWordContent([i-1 for i in res]))
+                yield W(res)
 
 class ShuffleProduct_overlapping(CombinatorialClass):
     def __init__(self, w1, w2):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.shuffle_product import ShuffleProduct_overlapping
             sage: w, u = map(Words("abcdef"), ["ab", "cd"])
             sage: S = ShuffleProduct_overlapping(w,u)
@@ -262,7 +262,7 @@
     def __repr__(self):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.shuffle_product import ShuffleProduct_overlapping
             sage: w, u = map(Words("abcdef"), ["ab", "cd"])
             sage: ShuffleProduct_overlapping(w,u).__repr__()
@@ -273,26 +273,17 @@
     def __iter__(self):
         """
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.shuffle_product import ShuffleProduct_overlapping
             sage: w, u = map(Words(range(10)), [[0,1],[2,3]])
             sage: S = ShuffleProduct_overlapping(w,u)
             sage: S.list()
-            [word: 0123, word: 0213, word: 0231, word: 2013, word: 2031, word: 2301, word: 313, word: 043, word: 331, word: 025, word: 241, word: 205, word: 35]
-        
-        ::
-        
+            [word: 0123, word: 0213, word: 0231, word: 2013, word: 2031, word: 2301, word: 213, word: 033, word: 231, word: 024, word: 231, word: 204, word: 24]
+
             sage: w, u = map(Words(range(1,10)), [[1,2],[3,4]])
             sage: S = ShuffleProduct_overlapping(w,u)
             sage: S.list()
             [word: 1234, word: 1324, word: 1342, word: 3124, word: 3142, word: 3412, word: 424, word: 154, word: 442, word: 136, word: 352, word: 316, word: 46]
-        
-        ::
-        
-            sage: w, u = map(Words("abcdef"), ["ab", "cd"])
-            sage: S = ShuffleProduct_overlapping(w,u)
-            sage: S.list() #indirect doctest
-            [word: abcd, word: acbd, word: acdb, word: cabd, word: cadb, word: cdab, word: dbd, word: aed, word: ddb, word: acf, word: ceb, word: caf, word: df]
         """
         m = len(self._w1)
         n = len(self._w2)
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/words/suffix_trees.py
--- a/sage/combinat/words/suffix_trees.py	Thu Jul 09 15:14:36 2009 -0700
+++ b/sage/combinat/words/suffix_trees.py	Fri Jul 17 23:25:52 2009 +0200
@@ -1,4 +1,4 @@
-"""
+r"""
 Suffix Tries and Suffix Trees
 """
 #*****************************************************************************
@@ -10,66 +10,63 @@
 #
 #                  http://www.gnu.org/licenses/
 #*****************************************************************************
-from itertools import chain
 from sage.structure.sage_object import SageObject
 from sage.graphs.graph import Graph, DiGraph
 from sage.graphs.graph_fast import spring_layout_fast
 from sage.misc.flatten import flatten
 from sage.sets.set import Set
-from sage.combinat.words.word import Words, FiniteWord_over_OrderedAlphabet
-from sage.combinat.words.word_content import BuildWordContent
-from sage.combinat.words.utils import reverse_map, isint
+from sage.combinat.words.word import Word, Words, FiniteWord_class
+from sage.rings.integer import Integer
+from itertools import izip
+from sage.misc.lazy_attribute import lazy_attribute
 
 ################################################################################
 # Suffix Tries
 ################################################################################
 
-# new unique object for the end of string symbol.
-end_of_string = object()
-
 class SuffixTrie(SageObject):
     def __init__(self, word):
         r"""
         Construct the suffix trie of the word w.
-        
+
         The suffix trie of a finite word w is a data structure representing
         the factors of w. It is a tree whose edges are labelled with
         letters of w, and whose leafs correspond to suffixes of w.
-        
+
         This is a straightforward implementation of Algorithm 1 from [1].
-        It constructs the suffix trie of w[:i] from that of w[:i-1].
-        
+        It constructs the suffix trie of w[:i] from that of w[:i-1]. 
+
         A suffix trie is modelled as a deterministic finite-state automaton
-        together with the suffix_link map. The set of states corresponds
-        to factors of the word (below we write x' for the state
-        corresponding to x); these are always 0, 1, .... The state 0 is the
-        initial state, and it corresponds to the empty word. For the
-        purposes of the algorithm, there is also an auxiliary state -1. The
-        transition function t is defined as::
+        together with the suffix_link map. The set of states corresponds to
+        factors of the word (below we write x' for the state corresponding
+        to x); these are always 0, 1, .... The state 0 is the initial
+        state, and it corresponds to the empty word.  For the purposes of
+        the algorithm, there is also an auxiliary state -1. The transition
+        function t is defined as::
 
-            t(-1,a) = 0 for all letters a; and
-            t(x',a) = y' for all x',y' `\in Q` such that y = xa,
+                t(-1,a) = 0 for all letters a; and
+                t(x',a) = y' for all x',y' \in Q such that y = xa,
 
         and the suffix link function is defined as::
 
-            suffix_link(0) = -1;
-            suffix_link(x') = y', if x = ay for some letter a.
-        
+                suffix_link(0) = -1;
+                suffix_link(x') = y', if x = ay for some letter a.
+
         REFERENCES:
 
-        - [1] E. Ukkonen, "On-line construction of suffix trees",
-          Algorithmica, 1995, volume 14, number 3, pages 249-260.
-        
+        - [1] E. Ukkonen, "On-line construction of suffix trees", 
+          Algorithmica, 1995, volume 14, number 3, pages 249--260.
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: w = Words("cao")("cacao")
             sage: t = SuffixTrie(w); t
             Suffix Trie of the word: cacao
-        
+
         ::
-        
-            sage: e = Words("ab")(format="empty")
+
+            sage: e = Words("ab")()
             sage: t = SuffixTrie(e); t
             Suffix Trie of the word:
             sage: t.process_letter("a"); t
@@ -78,9 +75,9 @@
             Suffix Trie of the word: ab
             sage: t.process_letter("a"); t
             Suffix Trie of the word: aba
-        
+
         TESTS::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: w = Words("cao")("cacao")
             sage: s = SuffixTrie(w)
@@ -91,23 +88,25 @@
         self._active_state = 0
         self._transition_function = {}
         self._suffix_link = [-1]
-        self._alphabet = word.alphabet()
+        self._alphabet = word.parent().alphabet()
 
         # Process each letter, in order.
-        W = Words(word.alphabet())
+        W = word.parent()
         w = W()
         for letter in word:
             self._process_letter(W([letter]))
 
-    def _process_letter(self,letter):
+    def _process_letter(self, letter):
         r"""
         Process a letter. That is, modify the current suffix trie producing
-        the suffix trie for self.word() + letter.
-        
-        NOTE: letter must occur within the alphabet of the word.
-        
+        the suffix trie for ``self.word() + letter``.
+ 
+        .. note::
+           
+           ``letter`` must occur within the alphabet of the word.
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: t = SuffixTrie(Word("ababba"))
             sage: t._process_letter(Words("ab")("b")); t
@@ -137,31 +136,34 @@
         self._active_state = \
                 self._transition_function[(self._active_state, letter)]
 
-    def process_letter(self,letter):
+    def process_letter(self, letter):
         r"""
-        Modify self to produce the suffix trie for self.word() + letter.
+        Modify ``self`` to produce the suffix trie for ``self.word() +
+        letter``.
+
+        .. note::
         
-        NOTE: letter must occur within the alphabet of the word.
-        
+           ``letter`` must occur within the alphabet of the word.
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: w = Words("ab")("ababba")
             sage: t = SuffixTrie(w); t
             Suffix Trie of the word: ababba
             sage: t.process_letter("a"); t
             Suffix Trie of the word: ababbaa
-        
+
         TESTS::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: w = Words("cao")("cacao")
             sage: t = SuffixTrie(w); t
             Suffix Trie of the word: cacao
             sage: t.process_letter("d")
             Traceback (most recent call last):
-                ...
-            IndexError: letter not in alphabet: 'd'
+            ...
+            ValueError: d not in alphabet!
         """
         # Make certain that letter is a word containing one letter.
         letter = Words(self._alphabet)([letter])
@@ -176,7 +178,7 @@
     def _repr_(self):
         """
         TESTS::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: SuffixTrie(Word("abcba"))._repr_()
             'Suffix Trie of the word: abcba'
@@ -186,10 +188,14 @@
     def node_to_word(self, state=0):
         r"""
         Returns the word obtained by reading the edge labels from 0 to
-        state.
-        
+        ``state``.
+
+        INPUT:
+
+        - ``state`` - (default: 0) a state
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: w = Words("abc")("abcba")
             sage: t = SuffixTrie(w)
@@ -201,7 +207,8 @@
         if state == 0:
             return Words(self._alphabet)()
         # We first invert the transition function
-        tf_inv = reverse_map(self._transition_function)
+        tf_inv = dict(izip(self._transition_function.itervalues(),
+                            self._transition_function))
         # Starting from the active state, 
         # read labels along the unique path to the root.
         (u,letter) = tf_inv[state]
@@ -216,9 +223,9 @@
     def word(self):
         r"""
         Returns the word whose suffix tree this is.
-        
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: w = Words("abc")("abcba")
             sage: t = SuffixTrie(w)
@@ -233,9 +240,9 @@
         r"""
         If self and other have the same transition function, the same
         suffix link, and the same word, then they are equal.
-        
-        TEST::
-        
+
+        TESTS::
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: SuffixTrie(Word("cacao")) == SuffixTrie(Word("ababc"))
             False
@@ -258,11 +265,16 @@
 
     def transition_function(self, node, word):
         r"""
-        Returns the state reached by beginning at node and following the
-        arrows in the transition graph labelled by the letters of word.
-        
+        Returns the state reached by beginning at ``node`` and following the
+        arrows in the transition graph labelled by the letters of ``word``. 
+
+        INPUT:
+
+        - ``node`` - a node
+        - ``word`` - a word
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: w = Words([0,1])([0,1,0,1,1])
             sage: t = SuffixTrie(w)
@@ -273,9 +285,9 @@
         """
         if node == -1:
             return self.transition_function(0, word[1:])
-        if len(word) == 0:
+        if word.is_empty():
             return 0
-        if len(word) == 1:
+        if word.length() == 1:
             return self._transition_function[(node,word)]
         else:
             return self.transition_function( \
@@ -284,17 +296,17 @@
     def states(self):
         r"""
         Returns the states of the automaton defined by the suffix trie.
-        
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: w = Words([0,1])([0,1,1])
             sage: t = SuffixTrie(w)
             sage: t.states()
             [0, 1, 2, 3, 4]
-        
+
         ::
-        
+
             sage: u = Words("aco")("cacao")
             sage: s = SuffixTrie(u)
             sage: s.states()
@@ -304,11 +316,15 @@
 
     def suffix_link(self, state):
         r"""
-        Evaluates the suffix link map of the suffix trie on state. Note
-        that the suffix link map is not defined on -1.
-        
+        Evaluates the suffix link map of the suffix trie on ``state``.
+        Note that the suffix link map is not defined on -1.
+
+        INPUT:
+
+        - ``state`` - a state
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: w = Words("cao")("cacao")
             sage: t = SuffixTrie(w)
@@ -316,26 +332,26 @@
             [-1, 0, 3, 0, 5, 1, 7, 2, 9, 10, 11, 12, 0]
             sage: t.suffix_link(0)
             -1
-        
+
         TESTS::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: w = Words("cao")("cacao")
             sage: t = SuffixTrie(w)
             sage: t.suffix_link([1])
             Traceback (most recent call last):
-                ...
+            ...
             TypeError: [1] is not an integer
             sage: t.suffix_link(-1)
             Traceback (most recent call last):
-                ...
+            ...
             TypeError: suffix link is not defined for -1
             sage: t.suffix_link(17)
             Traceback (most recent call last):
-                ...
+            ...
             TypeError: 17 is not a state
         """
-        if not isint(state):
+        if not isinstance(state, (int,Integer)):
             raise TypeError, "%s is not an integer" % state
         if state == -1:
             raise TypeError, "suffix link is not defined for -1"
@@ -346,18 +362,18 @@
     def active_state(self):
         r"""
         Returns the active state of the suffix trie. This is the state
-        corresponding to the word as a suffix of itself.
-        
+        corresponding to the word as a suffix of itself.  
+ 
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: w = Words("cao")("cacao")
             sage: t = SuffixTrie(w)
             sage: t.active_state()
             8
-        
+
         ::
-        
+
             sage: u = Words([0,1])([0,1,1,0,1,0,0,1])
             sage: s = SuffixTrie(u)
             sage: s.active_state()
@@ -368,12 +384,12 @@
     def final_states(self):
         r"""
         Returns the set of final states of the suffix trie. These are the
-        states corresponding to the suffixes of self.word(). They are
+        states corresponding to the suffixes of ``self.word()``. They are
         obtained be repeatedly following the suffix link from the active
         state until we reach 0.
-        
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: w = Words("cao")("cacao")
             sage: t = SuffixTrie(w)
@@ -389,16 +405,16 @@
 
     def has_suffix(self,word):
         r"""
-        Return True if and only if word is a suffix of self.word().
-        
+        Return ``True`` if and only if ``word`` is a suffix of ``self.word()``.
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: w = Words("cao")("cacao")
             sage: t = SuffixTrie(w)
-            sage: [t.has_suffix(w[i:]) for i in range(len(w)+1)]
+            sage: [t.has_suffix(w[i:]) for i in range(w.length()+1)]
             [True, True, True, True, True, True]
-            sage: [t.has_suffix(w[:i]) for i in range(len(w)+1)]
+            sage: [t.has_suffix(w[:i]) for i in range(w.length()+1)]
             [True, False, False, False, False, True]
         """
         # Find the state corresponding to word, and
@@ -416,11 +432,11 @@
 
     def to_digraph(self):
         r"""
-        Returns a DiGraph object of the transition graph of the suffix
+        Returns a ``DiGraph`` object of the transition graph of the suffix 
         trie.
-        
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: w = Words("cao")("cac")
             sage: t = SuffixTrie(w)
@@ -444,14 +460,14 @@
         r"""
         Returns a Graphics object corresponding to the transition graph of
         the suffix trie.
-        
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: SuffixTrie(Word("cacao")).plot()
-        
+
         TESTS::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: type(SuffixTrie(Word("cacao")).plot())
             <class 'sage.plot.plot.Graphics'>
@@ -470,10 +486,10 @@
 
     def show(self, *args, **kwds):
         r"""
-        Displays the output of self.plot().
-        
+        Displays the output of ``self.plot()``.
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import SuffixTrie
             sage: w = Words("cao")("cac")
             sage: t = SuffixTrie(w)
@@ -490,62 +506,62 @@
     def __init__(self, word):
         r"""
         Construct the implicit suffix tree of a word w.
-        
+
         The suffix tree of a word w is a compactification of the suffix
         trie for w. The compactification removes all nodes that have
         exactly one incoming edge and exactly one outgoing edge. It
         consists of two components: a tree and a word. Thus, instead of
         labelling the edges by factors of w, we can labelled them by
-        indices of the occurrence of the factors in w.
-        
+        indices of the occurrence of the factors in w. 
+
         The following is a straightforward implementation of Ukkonen's
-        on-line algorithm for constructing the implicit suffix tree [1]. It
-        constructs the suffix tree for w[:i] from that of w[:i-1].
-        
+        on-line algorithm for constructing the implicit suffix tree [1].
+        It constructs the suffix tree for w[:i] from that of w[:i-1]. 
+
         GENERAL IDEA. The suffix tree of w[:i+1] can be obtained from that
         of w[:i] by visiting each node corresponding to a suffix of w[:i]
         and modifying the tree by applying one of two rules (either append
         a new node to the tree, or split an edge into two). The "active
         state" is the node where the algorithm begins and the "suffix link"
         carries us to the next node that needs to be dealt with.
-        
+
         TREE. The tree is modelled as an automaton, which is stored as a
         dictionary of dictionaries: it is keyed by the nodes of the tree,
-        and the corresponding dictionary is keyed by pairs (i,j) of
+        and the corresponding dictionary is keyed by pairs `(i,j)` of
         integers representing the word w[i-1:j]. This makes it faster to
         look up a particular transition beginning at a specific node.
-        
+
         STATES/NODES. The states will always be -1, 0, 1, ..., n. The state
         -1 is special and is only used for the purposes of the algorithm.
         All transitions map -1 to 0, so this information is not explicitly
         stored in the transition function.
-        
+
         EXPLICIT/IMPLICIT NODES. By definition, some of the nodes will not
         be states, but merely locations along an edge; these are called
         implicit nodes. A node r (implicit or explicit) is referenced as a
         pair (s,(k,p)) where s is an ancestor of r and w[k-1:p] is the word
         read by transitioning from s to r in the suffix trie. A reference
-        pair is canonical if s is the closest ancestor of r.
-        
+        pair is canonical if s is the closest ancestor of r. 
+
         SUFFIX LINK. The algorithm makes use of a map from (some) nodes to
         other nodes, called the suffix link. This is stored as a
         dictionary.
-        
+
         ACTIVE STATE. We store as ._active_state the active state of the
         tree, the state where the algorithm will begin when processing the
         next letter.
-        
+
         RUNNING TIME. The running time and storage space of the algorithm
         is linear in the length of the word w (whereas for a suffix tree it
-        is quadratic).
-        
+        is quadratic). 
+
         REFERENCES:
 
-        - [1] E. Ukkonen, "On-line construction of suffix trees",
-          Algorithmica, 1995, volume 14, number 3, pages 249-260.
-        
+        - [1] E. Ukkonen, "On-line construction of suffix trees", 
+          Algorithmica, 1995, volume 14, number 3, pages 249--260.
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: w = Words("aco")("cacao")
             sage: t = ImplicitSuffixTree(w); t
@@ -553,9 +569,9 @@
             sage: ababb = Words([0,1])([0,1,0,1,1])
             sage: s = ImplicitSuffixTree(ababb); s
             Implicit Suffix Tree of the word: 01011
-        
+
         TESTS::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: w = Words("cao")("cacao")
             sage: s = ImplicitSuffixTree(w)
@@ -566,44 +582,68 @@
         self._transition_function = {0:{}}
         self._suffix_link = {0:-1}
         self._active_state = (0,(1,1))
-        self._word_content = []
-        for letter in word._word_content:
-            self._word_content.append(letter)
+        self._letters = []
+        for letter in word:
+            self._letters.append(letter)
             self._process_letter(letter)
         # _word is not needed for constructing the suffix tree, 
         # but it is useful for the other methods.
         self._word = word
 
+    @lazy_attribute
+    def _word_content(self):
+        r"""
+        This function is deprecated, use _letters instead.
+
+        EXAMPLES::
+
+            sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
+            sage: w = Words('cao')('cacao')
+            sage: s = ImplicitSuffixTree(w)
+            sage: s._word_content
+            doctest:492: DeprecationWarning: _word_content is deprecated, use _letters instead
+            ['c', 'a', 'c', 'a', 'o']
+        """
+        from sage.misc.misc import deprecation
+        deprecation("_word_content is deprecated, use _letters instead")
+        return self._letters
+
     def _process_letter(self, letter):
         r"""
         This is the main part of Ukkonen's algorithm. This corresponds to
         the algorithm "update" in [1].
-        
+
+        .. note::
+
+           This function is a helper and does not update ``self._data`` and
+           ``self._word``.
+
         REFERENCES:
 
-        - [1] E. Ukkonen, "On-line construction of suffix trees",
-          Algorithmica, 1995, volume 14, number 3, pages 249-260.
-        
+        - [1] E. Ukkonen, "On-line construction of suffix trees", 
+          Algorithmica, 1995, volume 14, number 3, pages 249--260.
+
         TESTS::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: w = Words("aco")("caca")
             sage: t = ImplicitSuffixTree(w); t
             Implicit Suffix Tree of the word: caca
-            sage: new_letter = w.alphabet().rank("o")
-            sage: t._word_content.append(new_letter)
-            sage: t._process_letter(new_letter)
+            sage: new_letter = "o"
+            sage: t._letters.append("o")
+            sage: t._process_letter("o")
+            sage: t._word = Words("aco")("cacao")
             sage: t
             Implicit Suffix Tree of the word: cacao
-        
+
         ::
-        
+
             sage: W = Words([0,1])
             sage: s = ImplicitSuffixTree(W([0,1,0,1])); s
             Implicit Suffix Tree of the word: 0101
-            sage: new_letter = W.alphabet().rank(1)
-            sage: s._word_content.append(new_letter)
-            sage: s._process_letter(new_letter)
+            sage: s._letters.append(1)
+            sage: s._process_letter(1)
+            sage: s._word = W([0,1,0,1,1])
             sage: s
             Implicit Suffix Tree of the word: 01011
         """
@@ -633,22 +673,22 @@
     def _test_and_split(self, s, (k, p), letter):
         r"""
         Helper function for _process_letter. Tests to see whether an edge
-        needs to be split. Returns (True, state), where state is the next
-        state to process (either a newly created state or the original s).
-        
+        needs to be split. Returns ``(True, state)``, where ``state`` is the 
+        next state to process (either a newly created state or the original s).
+
         TESTS::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: w = Words("aco")("caca")
             sage: t = ImplicitSuffixTree(w)
-            sage: t._word_content.append(w.alphabet().rank("o"))
-            sage: t._test_and_split(0, (4,5), w.alphabet().rank("o"))
+            sage: t._letters.append(w.parent().alphabet().rank("o"))
+            sage: t._test_and_split(0, (4,5), w.parent().alphabet().rank("o"))
             (False, 3)
         """
         if k <= p:
             # find the transition from s that begins with k-th letter
-            ((kk,pp), ss) = self._find_transition(s, self._word_content[k-1])
-            if letter == self._word_content[kk + p - k]:
+            ((kk,pp), ss) = self._find_transition(s, self._letters[k-1])
+            if letter == self._letters[kk + p - k]:
                 return (True, s)
             else:
                 # replace transition above by transitions
@@ -668,15 +708,15 @@
     def _canonize(self, s, (k, p)):
         r"""
         Given an implicit or explicit reference pair for a node, returns
-        the canonical reference pair.
+        the canonical reference pair. 
         
         Recall that a node r is referenced as (s, (k,p)), where s is an
         ancestor or r and w[k-1:p] is the word obtained by reading the edge
         labels along the path from s to r. A reference pair is canonical if
-        s is the closest ancestor of r.
-        
+        s is the closest ancestor of r. 
+
         TESTS::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: t = ImplicitSuffixTree(Word("cacao"))
             sage: t._canonize(0,(3,5))
@@ -687,41 +727,41 @@
         if p < k:
             return (s,k)
         else:
-            ((kk,pp), ss) = self._find_transition(s, self._word_content[k-1])
+            ((kk,pp), ss) = self._find_transition(s, self._letters[k-1])
             while pp is not None and pp - kk <= p - k:
                 k = k + pp - kk + 1
                 s = ss
                 if k <= p:
-                    ((kk,pp), ss) = self._find_transition(s, self._word_content[k-1])
+                    ((kk,pp), ss) = self._find_transition(s, self._letters[k-1])
             return (s, k)
 
     def _find_transition(self, state, letter):
         r"""
         Returns the transition from state that begins with letter. Returns
-        None if no such transition exists.
-        
+        ``None`` if no such transition exists.
+
         The transitions are stored as a dictionary of dictionaries: keyed
         by the nodes, with the corresponding dictionary keyed by pairs
-        (i,j) of integers representing the word w[i-1:j].
-        
-        ._transition_function = ..., node: (i,j): target_node, ...
-        
+        `(i,j)` of integers representing the word w[i-1:j].
+
+        ._transition_function = {..., node: {(i,j): target_node, ...} }
+
         TESTS::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: t = ImplicitSuffixTree(Word("cacao"))
-            sage: t._find_transition(-1, 1)
+            sage: t._find_transition(-1, "c")
             ((0, 0), 0)
-            sage: t._find_transition(0, 0)
+            sage: t._find_transition(0, "a")
             ((2, 2), 5)
-            sage: t._find_transition(0, 1)
+            sage: t._find_transition(0, "c")
             ((1, 2), 3)
-            sage: t._find_transition(5, 1)
+            sage: t._find_transition(5, "c")
             ((3, None), 2)
-            sage: t._find_transition(5, 0)
-        
+            sage: t._find_transition(5, "a")
+
         ::
-        
+
             sage: t = ImplicitSuffixTree(Word([0,1,0,1,1]))
             sage: t._find_transition(3, 1)
             ((5, None), 4)
@@ -731,7 +771,7 @@
         else:
             if self._transition_function.has_key(state):
                 for ((k,p),s) in self._transition_function[state].iteritems():
-                    if self._word_content[k-1] == letter:
+                    if self._letters[k-1] == letter:
                         return ((k,p), s)
             return None
 
@@ -747,7 +787,7 @@
     def _repr_(self):
         r"""
         TESTS::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: ImplicitSuffixTree(Word("abcba"))._repr_()
             'Implicit Suffix Tree of the word: abcba'
@@ -757,30 +797,30 @@
     def word(self):
         r"""
         Returns the word whose implicit suffix tree this is.
-        
-        TEST::
-        
+
+        TESTS::
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: ImplicitSuffixTree(Word([0,1,0,1,0])).word() == Word([0,1,0,1,0])
             True
         """
-        return self._word.parent()(map(self._word.alphabet().unrank, self._word_content))
+        return self._word
 
     def transition_function_dictionary(self):
         r"""
         Returns the transition function as a dictionary of dictionaries.
-        The format is consistent with the input format for DiGraph.
-        
+        The format is consistent with the input format for ``DiGraph``.
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: W = Words("aco")
             sage: t = ImplicitSuffixTree(W("cac"))
             sage: t.transition_function_dictionary()
             {0: {1: (0, None), 2: (1, None)}}
-        
+
         ::
-        
+
             sage: W = Words([0,1])
             sage: t = ImplicitSuffixTree(W([0,1,0]))
             sage: t.transition_function_dictionary()
@@ -793,21 +833,23 @@
 
     def to_digraph(self, word_labels=False):
         r"""
-        Returns a DiGraph object of the transition graph of the suffix
-        tree.
-        
-        word_labels - if False, labels the edges by pairs (i, j); if True,
-        labels the edges by word[i:j].
-        
+        Returns a ``DiGraph`` object of the transition graph of the suffix tree.
+
+        INPUT:
+
+        -  ``word_labels`` - boolean (defaut: ``False``) if ``False``, labels 
+           the edges by pairs `(i, j)`; if ``True``, labels the edges by 
+           ``word[i:j]``.
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: W = Words([0,1,2])
             sage: t = ImplicitSuffixTree(W([0,1,0,1,2]))
             sage: t.to_digraph()
             Digraph on 8 vertices
         """
-        if self._word_content == []:
+        if self._letters == []:
             d = {0:{}}
             return DiGraph(d)
         d = self.transition_function_dictionary()
@@ -816,7 +858,7 @@
                 if word_labels:
                     d[u][v] = self._word[i:j]
                 elif j == None:
-                    d[u][v] = (i,len(self._word_content))
+                    d[u][v] = (i,len(self._letters))
         return DiGraph(d)
 
     def plot(self, word_labels=False, layout='tree', tree_root=0,
@@ -825,22 +867,26 @@
         r"""
         Returns a Graphics object corresponding to the transition graph of
         the suffix tree.
-        
+
         INPUT:
-        
-        
-        -  ``word_labels`` - if False, labels the edges by
-           pairs (i, j); if True, labels the edges by word[i:j].
-        
-        
+
+        -  ``word_labels`` - boolean (defaut: ``False``) if ``False``, labels
+           the edges by pairs `(i, j)`; if ``True``, labels the edges by 
+           ``word[i:j]``.
+        -  ``layout`` - (defaut: ``'tree'``)
+        -  ``tree_root`` - (defaut: 0)
+        -  ``tree_orientation`` - (defaut: ``'up'``)
+        -  ``vertex_colors`` - (defaut: ``None``)
+        -  ``edge_labels`` - (defaut: ``True``)
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: ImplicitSuffixTree(Word('cacao')).plot(word_labels=True)
             sage: ImplicitSuffixTree(Word('cacao')).plot(word_labels=False)
-        
+
         TESTS::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: type(ImplicitSuffixTree(Word('cacao')).plot(word_labels=True))
             <class 'sage.plot.plot.Graphics'>
@@ -860,17 +906,16 @@
 
     def show(self, word_labels=None, *args, **kwds):
         r"""
-        Displays the output of self.plot().
-        
+        Displays the output of ``self.plot()``.
+
         INPUT:
-        
-        
-        -  ``word_labels`` - if False, labels the edges by
-           pairs (i, j); if True, labels the edges by word[i:j].
-        
-        
+
+        -  ``word_labels`` - (default: ``None``) if ``False``, labels the 
+           edges by pairs `(i, j)`; if ``True``, labels the edges by 
+           ``word[i:j]``.
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: w = Words("cao")("cacao")
             sage: t = ImplicitSuffixTree(w)
@@ -887,11 +932,11 @@
 
     def __eq__(self,other):
         r"""
-        If self and other have the same transition function and the same
-        word, then they are equal.
-        
-        TEST::
-        
+        If self and other have the same transition function and the
+        same word, then they are equal.
+
+        TESTS::
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: w = Words([0,1,2])([0,1,0,1,2])
             sage: u = Words([0,1,2])(iter([0,1,0,1,2]))[:5]
@@ -901,17 +946,22 @@
         if not isinstance(other,ImplicitSuffixTree):
             return False
         return self._transition_function == other._transition_function \
-            and self._word_content == other._word_content
+            and self._letters == other._letters
 
-    def transition_function(self,word,node=0):
+    def transition_function(self, word, node=0):
         r"""
-        Returns the node obtained by starting from node and following the
-        edges labelled by the letters of word. Returns ("explicit",
-        end_node) if we end at end_node, or ("implicit", (edge, d)) if we
-        end d spots along an edge.
+        Returns the node obtained by starting from ``node`` and following the
+        edges labelled by the letters of ``word``. Returns ``("explicit",
+        end_node)`` if we end at ``end_node``, or ``("implicit", (edge, d))`` 
+        if we end `d` spots along an edge.
+
+        INPUT:
+        
+        - ``word`` - a word
+        - ``node`` - (default: 0) starting node
         
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: W = Words([0,1,2])
             sage: t = ImplicitSuffixTree(W([0,1,0,1,2]))
@@ -924,20 +974,20 @@
             sage: t.transition_function(W([0,1]), 5)
             ('implicit', (5, 2), 2)
         """
-        if len(word) == 0:
+        if word.is_empty():
             return "explicit", node
-        ((k,p),s) = self._find_transition(node, word._word_content[0])
+        ((k,p),s) = self._find_transition(node, word[0])
         if p is None:
-            # test that word is a prefix of self._word_content[k-1:]
-            if word == self._word[k-1:(k-1)+len(word)]:
-                if len(word) == len(self._word_content) - k + 1:
+            # test that word is a prefix of self._letters[k-1:]
+            if word == self._word[k-1:(k-1)+word.length()]:
+                if word.length() == len(self._letters) - k + 1:
                     return "explicit", s
                 else:
                     edge = (node,s)
-                    return "implicit", edge, len(word)
+                    return "implicit", edge, word.length()
         else:
             # find longest common prefix
-            m = min(p-k+1,len(word))
+            m = min(p-k+1,word.length())
             i = 0
             while i < m and self._word[k-1+i] == word[i]:
                 i += 1
@@ -951,9 +1001,9 @@
     def states(self):
         r"""
         Returns the states (explicit nodes) of the suffix tree.
-        
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: W = Words([0,1,2])
             sage: t = ImplicitSuffixTree(W([0,1,0,1,2]))
@@ -964,15 +1014,19 @@
 
     def suffix_link(self, state):
         r"""
-        Evaluates the suffix link map of the implicit suffix tree on state.
+        Evaluates the suffix link map of the implicit suffix tree on ``state``.
         Note that the suffix link is not defined for all states.
-        
-        The suffix link of a state x' that corresponds to the suffix x is
-        defined to be -1 is x' is the root (0) and y' otherwise, where y'
-        is the state corresponding to the suffix x[1:].
-        
+
+        The suffix link of a state `x'` that corresponds to the suffix `x` is
+        defined to be -1 is `x'` is the root (0) and `y'` otherwise, where `y'`
+        is the state corresponding to the suffix ``x[1:]``.
+
+        INPUT:
+
+        - ``state`` - a state
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: W = Words([0,1,2])
             sage: t = ImplicitSuffixTree(W([0,1,0,1,2]))
@@ -995,9 +1049,9 @@
     def active_state(self):
         r"""
         Returns the active state of the suffix tree.
-        
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: W = Words([0,1,2])
             sage: t = ImplicitSuffixTree(W([0,1,0,1,2]))
@@ -1009,72 +1063,70 @@
     def process_letter(self, letter):
         r"""
         Modifies the current implicit suffix tree producing the implicit
-        suffix tree for self.word() + letter.
-        
+        suffix tree for ``self.word() + letter``.
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: w = Words("aco")("cacao")
             sage: t = ImplicitSuffixTree(w[:-1]); t
             Implicit Suffix Tree of the word: caca
             sage: t.process_letter(w[-1]); t
             Implicit Suffix Tree of the word: cacao
-        
+
         ::
-        
+
             sage: W = Words([0,1])
             sage: s = ImplicitSuffixTree(W([0,1,0,1])); s
             Implicit Suffix Tree of the word: 0101
             sage: s.process_letter(W([1])[0]); s
             Implicit Suffix Tree of the word: 01011
         """
-        letter2int = self._word.alphabet().rank
-        self._word_content.append(letter2int(letter))
-        self._process_letter(self._word_content[-1])
+        self._word = self._word * self._word._parent([letter])
+        self._letters.append(letter)
+        self._process_letter(letter)
 
     def to_explicit_suffix_tree(self):
         r"""
         Converts self to an explicit suffix tree. It is obtained by
-        processing an end of string letter as if it were a regular letter,
-        except that no new leaf nodes are created (thus, the only thing
-        that happens is that some implicit nodes become explicit).
-        
+        processing an end of string letter as if it were a regular
+        letter, except that no new leaf nodes are created (thus, the only
+        thing that happens is that some implicit nodes become explicit).
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: w = Words("aco")("cacao")
-            sage: t = ImplicitSuffixTree(w[:-1])
+            sage: t = ImplicitSuffixTree(w)
             sage: t.to_explicit_suffix_tree()
-        
+
         ::
-        
+
             sage: W = Words([0,1])
-            sage: s = ImplicitSuffixTree(W([0,1,0,1, 1]))
+            sage: s = ImplicitSuffixTree(W([0,1,0,1,1]))
             sage: s.to_explicit_suffix_tree()
         """
-        # test whether end_of_string appears in the word
-        alphabet = self._word.alphabet()
-        if end_of_string in alphabet:
-            raise TypeError, "word contains the end of string symbol"
-        # append the end of string symbol to the word and process the new letter
-        self._word_content.append(end_of_string)
+        # append a new unique symbol to the word and process the new letter
+        end_of_string = object()
+        self._letters.append(end_of_string)
         (s,(k,i)) = self._active_state
         old_r = 0
         (end_state, r) = self._test_and_split(s,(k,i-1), end_of_string)
         while end_state == False:
             (s, k) = self._canonize(self._suffix_link[s], (k,i-1))
             (end_state, r) = self._test_and_split(s, (k,i-1), end_of_string)
-        self._word_content = self._word_content[:-1]
+        # remove the end of string symbol from the word
+        self._letters.pop()
         return
 
     def edge_iterator(self):
         r"""
-        Returns an iterator over the edges of the suffix tree. The edge
-        from u to v labelled by (i,j) is returned as the tuple
-        (u,v,(i,j)).
-        
+        Returns an iterator over the edges of the suffix tree. The
+        edge from `u` to `v` labelled by `(i,j)` is returned as the tuple
+        `(u,v,(i,j))`.
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: sorted( ImplicitSuffixTree(Word("aaaaa")).edge_iterator() )
             [(0, 1, (0, None))]
@@ -1092,20 +1144,20 @@
 
     def number_of_factors(self,n=None):
         r"""
-        Count the number of distinct factors of self.word().
-        
+        Count the number of distinct factors of ``self.word()``.
+
         INPUT:
-        
-        
-        -  ``n`` - an integer, or None.
-        
-        
-        OUTPUT: If n is an integer, returns the number of distinct factors
-        of length n. If n is None, returns the total number of distinct
-        factors.
-        
+
+        -  ``n`` - an integer, or ``None``.
+
+        OUTPUT:
+
+        -  If ``n`` is an integer, returns the number of distinct factors
+           of length ``n``. If ``n`` is ``None``, returns the total number of
+           distinct factors.
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: t = ImplicitSuffixTree(Word([1,2,1,3,1,2,1]))
             sage: t.number_of_factors()
@@ -1116,17 +1168,17 @@
             0
             sage: t.number_of_factors(0)
             1
-        
+
         ::
-        
+
             sage: t = ImplicitSuffixTree(Word("cacao"))
             sage: t.number_of_factors()
             13
             sage: map(t.number_of_factors, range(10))
             [1, 3, 3, 3, 2, 1, 0, 0, 0, 0]
-        
+
         ::
-        
+
             sage: t = ImplicitSuffixTree(Word("c"*1000))
             sage: t.number_of_factors()
             1001
@@ -1134,14 +1186,14 @@
             1
             sage: t.number_of_factors(0)
             1
-        
+
         ::
-        
+
             sage: ImplicitSuffixTree(Word()).number_of_factors()
             1
-        
+
         ::
-        
+
             sage: blueberry = ImplicitSuffixTree(Word("blueberry"))
             sage: blueberry.number_of_factors()
             43
@@ -1149,15 +1201,15 @@
             [1, 6, 8, 7, 6, 5, 4, 3, 2, 1]
         """
         if n is None:
-            length_word = len(self.word())
+            length_word = self.word().length()
             num_factors = 1 # empty word
             for (u,v,(i,j)) in self.edge_iterator():
                 if j == None:
                     num_factors += length_word - i
                 else:
                     num_factors += j - i
-        elif isint(n):
-            length_word = len(self.word())
+        elif isinstance(n, (int,Integer)):
+            length_word = self.word().length()
             num_factors = 0
             queue = [(0, 0)]
             while queue:
@@ -1168,7 +1220,7 @@
                     if self._transition_function[v] != {}:
                         for ((i,j),u) in self._transition_function[v].iteritems():
                             if j == None: 
-                                j = len(self.word())
+                                j = self.word().length()
                             if j - i >= n - l:
                                 num_factors += 1
                             else:
@@ -1179,20 +1231,20 @@
 
     def factor_iterator(self,n=None):
         r"""
-        Generate distinct factors of self.
-        
+        Generate distinct factors of ``self``.
+
         INPUT:
-        
-        
-        -  ``n`` - an integer, or None.
-        
-        
-        OUTPUT: If n is an integer, returns an iterator over all distinct
-        factors of length n. If n is None, returns an iterator generating
-        all distinct factors.
+
+        -  ``n`` - an integer, or ``None``.
+
+        OUTPUT:
+
+        -  If ``n`` is an integer, returns an iterator over all distinct
+           factors of length ``n``. If ``n`` is ``None``, returns an iterator
+           generating all distinct factors.
         
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
             sage: sorted( ImplicitSuffixTree(Word("cacao")).factor_iterator() )
             [word: , word: a, word: ac, word: aca, word: acao, word: ao, word: c, word: ca, word: cac, word: caca, word: cacao, word: cao, word: o]
@@ -1221,22 +1273,22 @@
                 if self._transition_function[v] != {}:
                     for ((i,j),u) in self._transition_function[v].iteritems():
                         if j == None:
-                            j = len(self.word())
+                            j = self.word().length()
                         for k in range(i,j):
                             yield w * self.word()[i-1:k]
                         queue.append((u,w*self.word()[i-1:j]))
-        elif isint(n):
+        elif isinstance(n, (int,Integer)):
             queue = [(0, self._word.parent()())]
             while queue:
                 (v,w) = queue.pop()
-                length_w = len(w)
+                length_w = w.length()
                 if length_w == n:
                     yield w
                 if length_w < n:
                     if self._transition_function[v] != {}:
                         for ((i,j),u) in self._transition_function[v].iteritems():
                             if j == None: 
-                                j = len(self.word())
+                                j = self.word().length()
                             if j - i >= n - length_w:
                                 yield w*self.word()[i-1:i-1+n-length_w]
                             else:
@@ -1253,9 +1305,9 @@
         Returns the tree obtained from self by splitting edges so that they
         are labelled by exactly one letter. The resulting tree is
         isomorphic to the suffix trie.
-        
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree, SuffixTrie
             sage: abbab = Words("ab")("abbab")
             sage: s = SuffixTrie(abbab)
@@ -1283,9 +1335,9 @@
         r"""
         Returns a dictionary in a format compatible with that of the suffix
         trie transition function.
-        
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree, SuffixTrie
             sage: W = Words("ab")
             sage: t = ImplicitSuffixTree(W("aba"))
@@ -1297,11 +1349,11 @@
         for (u, dd) in self._transition_function.iteritems():
             for (sl, v) in dd.iteritems():
                 w = self._word[sl[0]-1:sl[1]]
-                if len(w) == 1:
+                if w.length() == 1:
                     d[u,w] = v
                 else:
                     d[u,w[0:1]] = new_node
-                    for i in range(1,len(w)-1):
+                    for i in range(1,w.length()-1):
                         d[new_node, w[i:i+1]] = new_node + 1
                         new_node += 1
                     d[new_node,w[-1:]] = v
@@ -1316,29 +1368,27 @@
     r"""
     Given a word, constructs the suffix tree of the word using a naive
     algorithm. Useful for testing.
-    
+
     INPUT:
-    
-    
+
     -  ``word`` - any word
-    
-    
+
     EXAMPLES::
-    
+
         sage: from sage.combinat.words.suffix_trees import NaiveSuffixTree
         sage: W = Words('abco')
         sage: s = NaiveSuffixTree(W("abacabaabaca")); s
         Suffix Tree of the word: abacabaabaca
-    
+
     ::
-    
+
         sage: s = NaiveSuffixTree(W("cacao")); s
         Suffix Tree of the word: cacao
         sage: s.edges()
         [(0, 3, word: ca), (0, 5, word: a), (0, 7, word: o), (3, 1, word: cao), (3, 4, word: o), (5, 2, word: cao), (5, 6, word: o)] 
-    
+
     ::
-    
+
         sage: W = Words([0,1])
         sage: s = NaiveSuffixTree(W([0,1,0,1,1])); s
         Suffix Tree of the word: 01011
@@ -1349,22 +1399,22 @@
     ST = NaiveSuffixTreeClass({0:[]})
     ST.set_vertex(0,{'position':0,'suffix':True})
 
-    # test whether the end of string symbol appears in the word
-    alphabet = word.alphabet()
-    if end_of_string in alphabet: 
-        raise TypeError, "word contains the end of string symbol"
-    # append end_of_string to the word and process the new letter
-    W = Words(chain(alphabet, [end_of_string]))
-    word *= W([end_of_string])
+    # append a new unique symbol to the word and process the new letter
+    end_of_string = object()
+    # HACK! Fix this after multiplication of words is better implemented.
+    #from itertools import chain
+    #W = Words(chain(word._parent._alphabet, [end_of_string]))
+    #word *= W([end_of_string])
+    word = Word(list(word) + [end_of_string])
 
     # run the algorithm
-    for i in range(len(word)):
+    for i in range(word.length()):
         ST.naive_process_suffix(word[i:])
 
     # prune the tree (remove end_of_string).
     for (u,v,l) in ST.edges():
         if l[-1] == end_of_string:
-            if l == W([end_of_string]):
+            if l.length() == 1:
                 ST.delete_edge(u,v)
                 ST.delete_vertex(v)
             else:
@@ -1373,16 +1423,22 @@
 
 class NaiveSuffixTreeClass(DiGraph):
 
-    def word_to_node(self,node,word):
+    def word_to_node(self, node, word):
         r"""
-        Returns the node obtained by starting from node and following the
-        edges labelled by the letters of word. Returns ("node", node2,
-        word2) if we end at node2, or ("implicit", edge, word2) if we end
-        in the middle of an edge (called an implicit node), where word2 is
-        the suffix of word that does not match any more edge labels.
-        
+        Returns the node obtained by starting from ``node`` and following
+        the edges labelled by the letters of ``word``. Returns ``("node",
+        node2, word2)`` if we end at ``node2``, or ``("implicit", edge, word2)``
+        if we end in the middle of an edge (called an implicit node),
+        where ``word2`` is the suffix of ``word`` that does not match any more
+        edge labels.
+
+        INPUT:
+
+        - ``node`` - a node
+        - ``word`` - a word
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import NaiveSuffixTree
             sage: W = Words("abc")
             sage: NST = NaiveSuffixTree(W("abacabaabaca"))
@@ -1395,14 +1451,14 @@
             sage: NST.word_to_node(15, W("baabacabca"))
             ('node', 4, word: bca)
         """
-        if len(word) == 0:
+        if word.is_empty():
             return "node", node, word
         for v in self.successor_iterator(node):
             label = self.edge_label(node,v)
             if label[0] != word[0]:
                 continue
             # find longest common prefix
-            m = min(len(label),len(word))
+            m = min(len(label),word.length())
             i = 0
             while i < m and label[i] == word[i]:
                 i += 1
@@ -1419,7 +1475,7 @@
         Helper function for constructing the suffix tree.
         
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import NaiveSuffixTreeClass
             sage: W = Words([0,1,2])
             sage: NST = NaiveSuffixTreeClass({0:[]})
@@ -1456,15 +1512,15 @@
     def plot(self, layout='tree', tree_root=0, tree_orientation='up',
             vertex_colors=None, edge_labels=True, *args, **kwds):
         r"""
-        Returns a Graphics object associated to self.
-        
+        Returns a Graphics object associated to ``self``.
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import NaiveSuffixTree
             sage: NaiveSuffixTree(Word("abacabaabaca")).plot()
-        
+
         TESTS::
-        
+
             sage: from sage.combinat.words.suffix_trees import NaiveSuffixTree
             sage: type(NaiveSuffixTree(Word("abacabaabaca")).plot())
             <class 'sage.plot.plot.Graphics'>
@@ -1478,11 +1534,11 @@
 
     def node_to_word(self,node):
         r"""
-        Returns the word obtained by reading the edge labels from the root
-        to node.
-        
+        Returns the word obtained by reading the edge labels from the root to
+        node.
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import NaiveSuffixTree
             sage: NaiveSuffixTree(Word("abacabaabaca")).node_to_word(17)
             word: ca
@@ -1501,9 +1557,9 @@
     def word(self):
         r"""
         Returns the word whose suffix tree this is.
-        
+
         EXAMPLES::
-        
+
             sage: from sage.combinat.words.suffix_trees import NaiveSuffixTree
             sage: NaiveSuffixTree(Word("abcba")).word()
             word: abcba
@@ -1513,7 +1569,7 @@
     def _repr_(self):
         """
         TESTS::
-        
+
             sage: from sage.combinat.words.suffix_trees import NaiveSuffixTree
             sage: NaiveSuffixTree(Word("abcba"))._repr_()
             'Suffix Tree of the word: abcba'
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/words/utils.py
--- a/sage/combinat/words/utils.py	Thu Jul 09 15:14:36 2009 -0700
+++ b/sage/combinat/words/utils.py	Fri Jul 17 23:25:52 2009 +0200
@@ -1,5 +1,13 @@
 """
-Word utilities
+Word utilities (DEPRECATED) 
+
+.. note::
+
+    This module will be deleted in a future version of Sage. Most of the
+    commands here have been already deleted; only the commands needed for
+    unpickling word objects saved with older versions of Sage (pre 4.1) have
+    been kept (for now).
+
 """
 #*****************************************************************************
 #       Copyright (C) 2008 Arnaud Bergeron <abergeron@gmail.com>
@@ -15,6 +23,9 @@
 
 def copy_it(it):
     r"""
+    This function is deprecated and will be deleted in a future
+    version of Sage.
+
     Copy an iterator using its builtin __copy__ method if
     available, otherwise use itertools.tee(). Define __copy__ for
     your iterators. (See PEP 323)
@@ -42,6 +53,9 @@
 
 def slice_it(it, l, key):
     r"""
+    This function is deprecated and will be deleted in a future
+    version of Sage.
+
     Slice an iterator, supporting negative step sizes by expliciting
     the elements if needed.
     
@@ -75,6 +89,9 @@
 
 def peek_it(it):
     r"""
+    This function is deprecated and will be deleted in a future
+    version of Sage.
+
     Returns the first element of an iterator and returns an iterator at
     the same position as the original iterator
     
@@ -92,6 +109,9 @@
 
 def len_it(it):
     r"""
+    This function is deprecated and will be deleted in a future
+    version of Sage.
+
     Returns the number of elements in it.
     
     This function will modify the iterator, so if you want to access
@@ -114,6 +134,9 @@
 
 def haslen(obj):
     r"""
+    This function is deprecated and will be deleted in a future
+    version of Sage.
+
     Returns true if obj has a properly defined length
     
     EXAMPLES::
@@ -141,6 +164,9 @@
     
 def sliceable(obj):
     r"""
+    This function is deprecated and will be deleted in a future
+    version of Sage.
+
     Returns true if obj is completely sliceable, including negative
     step sizes
     
@@ -169,6 +195,9 @@
 
 def isint(obj):
     r"""
+    This function is deprecated and will be deleted in a future
+    version of Sage.
+
     Returns True if obj is an integer or a custom object representing
     an integer and False otherwise.
     
@@ -186,6 +215,9 @@
 
 def is_iterable(obj):
     r"""
+    This function is deprecated and will be deleted in a future
+    version of Sage.
+
     Returns true if the obj is iterable.
     
     EXAMPLES::
@@ -208,6 +240,9 @@
 
 def slice_ok(part):
     r"""
+    This function is deprecated and will be deleted in a future
+    version of Sage.
+
     Returns true if part is a slice and doesn't have funny values.
     
     EXAMPLES::
@@ -241,6 +276,9 @@
 
 def slice_indices(s, l):
     r"""
+    This function is deprecated and will be deleted in a future
+    version of Sage.
+
     Implement slice.indices without bugs.
     
     TESTS::
@@ -273,10 +311,12 @@
     if stop*step < start*step:
         stop = start
     return start, stop, step
-        
 
 def reverse_map(d):
     r"""
+    This function is deprecated and will be deleted in a future
+    version of Sage.
+
     Return a new dict with swapped keys and values
     
     EXAMPLES::
@@ -289,19 +329,31 @@
 
 def id_f(x):
     r"""
+    This function is deprecated and will be deleted in a future
+    version of Sage.
+
     Dummy identity function for when a function is required but none is
     desired.
     
+    .. note::
+
+       This function is needed required so that words saved in earlier versions
+       of Sage can be loaded; and will be deleted in a future version of Sage. 
+
     TESTS::
     
+        sage: from sage.combinat.words.utils import id_f
         sage: l = [1, 2, 3]
-        sage: l is sage.combinat.words.utils.id_f(l)
+        sage: l is id_f(l)
         True
     """
     return x
 
 def clamp(x, min, max):
     r"""
+    This function is deprecated and will be deleted in a future
+    version of Sage.
+
     Clamp a value between a maximum and a minimum.
     
     EXAMPLES::
@@ -321,27 +373,5 @@
     else:
         return x
 
-class Factorization(list):
-    r"""
-    A list subclass having a nicer representation for factorization of
-    words.
-    
-    TESTS::
-    
-        sage: f = sage.combinat.words.utils.Factorization()
-        sage: f == loads(dumps(f))
-        True
-    """
-    def __repr__(self):
-        r"""
-        Returns a string representation of the object.
-        
-        TESTS::
-        
-            sage: sage.combinat.words.utils.Factorization()
-            ()
-            sage: sage.combinat.words.utils.Factorization([Word('ab'), Word('ba')])
-            (ab.ba)
-        """
-        from word import FiniteWord_over_OrderedAlphabet
-        return '(%s)' % '.'.join(imap(FiniteWord_over_OrderedAlphabet.string_rep, self))
+from sage.combinat.words.word import Factorization
+
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/words/word.py
--- a/sage/combinat/words/word.py	Thu Jul 09 15:14:36 2009 -0700
+++ b/sage/combinat/words/word.py	Fri Jul 17 23:25:52 2009 +0200
@@ -1,4 +1,192 @@
 # coding=utf-8
+r"""
+Words of all kinds and algorithms
+
+AUTHORS:
+
+- Arnaud Bergeron
+- Amy Glen
+- Sébastien Labbé
+- Franco Saliola
+
+EXAMPLES:
+
+============
+Finite words
+============
+
+Finite words from python strings, lists and tuples::
+
+    sage: Word("abbabaab")
+    word: abbabaab
+    sage: Word([0, 1, 1, 0, 1, 0, 0, 1])
+    word: 01101001
+    sage: Word( ('a', 0, 5, 7, 'b', 9, 8) )
+    word: a057b98
+
+Finite words from functions::
+    
+    sage: f = lambda n : n%3
+    sage: Word(f, length=13)
+    word: 0120120120120
+
+Finite words from iterators::
+
+    sage: from itertools import count
+    sage: Word(count(), length=10)
+    word: 0123456789
+
+::
+
+    sage: Word( iter('abbccdef') )
+    word: abbccdef
+
+Finite words from words via concatenation::
+
+    sage: u = Word("abcccabba")
+    sage: v = Word([0, 4, 8, 8, 3])
+    sage: u * v
+    word: abcccabba04883
+    sage: v * u
+    word: 04883abcccabba
+    sage: u + v
+    word: abcccabba04883
+    sage: u^3 * v^(8/5)
+    word: abcccabbaabcccabbaabcccabba04883048
+
+Finite words from infinite words::
+
+    sage: vv = v^Infinity
+    sage: vv[10000:10015]
+    word: 048830488304883
+
+Finite words in a specific combinatorial class::
+
+    sage: W = Words("ab")
+    sage: W
+    Words over Ordered Alphabet ['a', 'b']
+    sage: W("abbabaab")
+    word: abbabaab
+    sage: W(["a","b","b","a","b","a","a","b"])
+    word: abbabaab
+    sage: W( iter('ababab') )
+    word: ababab
+
+Finite word as the image under a morphism::
+
+    sage: m = WordMorphism({0:[4,4,5,0],5:[0,5,5],4:[4,0,0,0]})
+    sage: m(0)
+    word: 4450
+    sage: m(0, order=2)
+    word: 400040000554450
+    sage: m(0, order=3)
+    word: 4000445044504450400044504450445044500550...
+
+==============
+Infinite words
+==============
+
+Periodic infinite words::
+
+    sage: v = Word([0, 4, 8, 8, 3])
+    sage: vv = v^Infinity
+    sage: vv
+    word: 0488304883048830488304883048830488304883...
+
+Infinite words from a function `f:\mathbb{N}\rightarrow A` 
+over an alphabet `A`::
+
+    sage: Word(lambda n: n%3)
+    word: 0120120120120120120120120120120120120120...
+
+::
+
+    sage: def t(n):
+    ...       return add(Integer(n).digits(base=2)) % 2
+    sage: Word(t, alphabet = [0, 1])
+    word: 0110100110010110100101100110100110010110...
+
+or as a one-liner::
+
+    sage: Word(lambda n : add(Integer(n).digits(base=2)) % 2, alphabet = [0, 1])
+    word: 0110100110010110100101100110100110010110...
+
+Infinite words from iterators::
+
+    sage: from itertools import count,repeat
+    sage: Word( repeat(4) )
+    word: 4444444444444444444444444444444444444444...
+    sage: Word( count() )
+    word: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,...
+
+Infinite words from morphism
+
+For example, let `A=\{a,b\}` and `\mu : A^* \rightarrow A^*` 
+be the morphism defined by `a\mapsto ab, b\mapsto ba`::
+
+    sage: mu = WordMorphism('a->ab,b->ba'); print mu
+    WordMorphism: a->ab, b->ba
+    sage: mu.fixed_point('a')
+    Fixed point beginning with 'a' of the morphism WordMorphism: a->ab, b->ba
+
+Infinite words in a specific combinatorial class::
+
+    sage: W = Words("ab"); W
+    Words over Ordered Alphabet ['a', 'b']
+    sage: f = lambda n : 'a' if n % 2 == 1 else 'b'
+    sage: W(f)
+    word: babababababababababababababababababababa...
+
+==============
+Word functions
+==============
+
+::
+
+    sage: w = Word('abaabbba'); w
+    word: abaabbba
+    sage: w.is_palindrome()
+    False
+    sage: w.is_lyndon()
+    False
+    sage: w.number_of_factors()
+    28
+    sage: w.critical_exponent()
+    3
+
+::
+
+    sage: print w.lyndon_factorization()
+    (ab.aabbb.a)
+    sage: print w.crochemore_factorization()
+    (a.b.a.ab.bb.a)
+
+::
+
+    sage: st = w.suffix_tree()
+    sage: st
+    Implicit Suffix Tree of the word: abaabbba
+    sage: st.show(word_labels=True)
+
+::
+    
+    sage: T = words.FibonacciWord('ab')
+    sage: T.longest_common_prefix(Word('abaabababbbbbb'))
+    word: abaababa
+
+As matrix and many other sage objects, words have a parent::
+
+    sage: u = Word('xyxxyxyyy')
+    sage: u.parent()
+    Words
+
+::
+
+    sage: v = Word('xyxxyxyyy', alphabet='xy')
+    sage: v.parent()
+    Words over Ordered Alphabet ['x', 'y']
+
+"""
 #*****************************************************************************
 #       Copyright (C) 2008 Arnaud Bergeron <abergeron@gmail.com>,
 #                          Amy Glen <amy.glen@gmail.com>,       
@@ -11,298 +199,284 @@
 #
 #                  http://www.gnu.org/licenses/
 #*****************************************************************************
-r"""
-Words of all kinds
-
-AUTHORS:
-
-- Arnaud Bergeron
-
-- Amy Glen
-
-- Sébastien Labbé
-
-- Franco Saliola
-
-EXAMPLES:
-
-We define the set of words over 'a' and 'b'.
-
-::
-
-    sage: W = Words('ab'); W
-    Words over Ordered Alphabet ['a', 'b']
-
-Then we can build some words in the set::
-
-    sage: W('abba')
-    word: abba
-
-If you try to use letters that are not the alphabet of the set you get an error::
-
-    sage: W([1, 2])
-    Traceback (most recent call last):
-    ...
-    IndexError: letter not in alphabet: 1
-
-You can also build infinite words backed by a function or an iterator!
-
-::
-
-    sage: def f(n):
-    ...     if n % 2 == 1:
-    ...         return 'a'
-    ...     else:
-    ...         return 'b'
-    ...
-    sage: W(f)
-    Infinite word over ['a', 'b']
-"""
 from itertools import tee, islice, ifilter, ifilterfalse, imap, izip, \
-                      starmap, count, repeat, dropwhile, chain, cycle
+                      starmap, count, dropwhile, chain, cycle, groupby
 from sage.structure.sage_object import SageObject
 from sage.sets.set import Set, is_Set
-from sage.rings.infinity import infinity
+from sage.rings.infinity import Infinity
 from sage.rings.integer import Integer
+from sage.rings.integer_ring import ZZ
 from sage.misc.latex import latex
-from sage.combinat.words.alphabet import OrderedAlphabet_class
-from sage.combinat.words.words import Words, is_Words
-from sage.combinat.words.word_content import BuildWordContent, is_WordContent
-from sage.combinat.words.utils import *
+from sage.combinat.words.words import Words, Words_all
 from sage.combinat.partition import Partition, Partitions
 from sage.combinat.combinat import CombinatorialClass
 from sage.combinat.permutation import Permutation, Permutation_class
 from sage.groups.perm_gps.permgroup_element import PermutationGroupElement
+from sage.combinat.words.word_options import word_options
 import copy
-
-word_options = {'identifier':'word: ', 'display':'string', 'truncate':True, 'truncate_length':40,
-        'letter_separator':','}
-
-def WordOptions(**kwargs):
-    """
-    Sets the global options for elements of the word class. The
-    defaults are for words to be displayed in list notation.
-    
+from word_datatypes import (WordDatatype_str,
+                            WordDatatype_list,
+                            WordDatatype_tuple)
+
+from word_infinite_datatypes import (
+                            WordDatatype_iter_with_caching,
+                            WordDatatype_iter,
+                            WordDatatype_callable_with_caching,
+                            WordDatatype_callable)
+from sage.misc.lazy_attribute import lazy_attribute
+from sage.combinat.combinat import CombinatorialObject
+
+# TODO. Word needs to be replaced by Word. Consider renameing
+# Word_class to Word and imbedding Word as its __call__ method.
+
+def Word(data=None, alphabet=None, length=None, datatype=None,
+        caching=True):
+    r"""
+    Construct a word.
+
     INPUT:
-    
-    
-    -  ``display`` - 'string' (default), or 'list', words
-       are displayed in string or list notation.
-    
-    -  ``truncate`` - boolean (default: True), whether to
-       truncate the string output of long words (see truncate_length
-       below).
-    
-    -  ``truncate_length`` - integer (default: 40), if the
-       length of the word is greater than this integer, then the word is
-       truncated.
-    
-    -  ``letter_separator`` - (string, default: ",") if
-       the string representation of letters have length greater than 1,
-       then the letters are separated by this string in the string
-       representation of the word.
-    
-    
-    If no parameters are set, then the function returns a copy of the
-    options dictionary.
-    
-    EXAMPLES::
-    
-        sage: w = Word([2,1,3,12])
-        sage: u = Word("abba")
-        sage: WordOptions(display='list')
-        sage: w
-        word: [2, 1, 3, 12]
-        sage: u
-        word: ['a', 'b', 'b', 'a']
-        sage: WordOptions(display='string')
-        sage: w
-        word: 2,1,3,12
-        sage: u
-        word: abba
-    """
-    global word_options
-    if kwargs == {}:
-        return copy.copy(word_options)
-
-    if 'display' in kwargs:
-        if kwargs['display'] not in ['list', 'string']:
-            raise ValueError, "display must be either 'list' or 'string'"
-        else:
-            word_options['display'] = kwargs['display']
-    elif 'truncate' in kwargs:
-        if not isinstance(kwargs['truncate'], bool):
-            raise ValueError, "truncate must be True or False"
-        else:
-            word_options['truncate'] = kwargs['truncate']
-    elif 'truncate_length' in kwargs:
-        if not isinstance(kwargs['truncate_length'], (int,Integer)) or kwargs['truncate_length'] <= 0:
-            raise ValueError, "truncate_length must be a positive integer"
-        else:
-            word_options['truncate_length'] = kwargs['truncate_length']
-    elif 'letter_separator' in kwargs:
-        if not isinstance(kwargs['letter_separator'], str):
-            raise ValueError, "letter_separator must be a string"
-        else:
-            word_options['letter_separator'] = kwargs['letter_separator']
-    elif 'identifier' in kwargs:
-        if not isinstance(kwargs['identifier'], str):
-            raise ValueError, "identifier must be a string"
-        else:
-            word_options['identifier'] = kwargs['identifier']
-
-def Word(data=None, alphabet=None):
-    r"""
-    Returns a word over the given alphabet.
-    
-    INPUT:
-    
-    
-    -  ``data`` - An iterable (list, string, iterator) or a
-       function defined on nonnegative integers that yields the letters of
-       the word.
-    
-    -  ``alphabet`` - An iterable yielding letters in their
-       comparative order. If alphabet is None and data is a string or
-       list, then the letters appearing in data, ordered by Python's
-       builtin sorted function, is used as alphabet.
-    
-    
-    OUTPUT: A FiniteWord_over_OrderedAlphabet or
-    InfiniteWord_over_OrderedAlphabet object.
-    
-    NOTE: Essentially, this function just returns
-    Words(alphabet)(data).
-    
-    EXAMPLES: 0. The empty word.
-    
-    ::
-    
+
+    -  ``data`` - (default: None) list, string, tuple, iterator, None
+       (shorthand for []), or a callable defined on [0,1,...,length].
+
+    -  ``alphabet`` - any argument accepted by Words
+
+    -  ``length`` - (default: None) This is dependent on the type of data. 
+       It is ignored for words defined by lists, strings, tuples,
+       etc., because they have a naturally defined length.
+       For callables, this defines the domain of definition,
+       which is assumed to be [0, 1, 2, ..., length-1].
+       For iterators: Infinity if you know the iterator will not
+       terminate (default); "unknown" if you do not know whether the
+       iterator terminates; "finite" if you know that the iterator
+       terminates, but do know know the length.
+
+    -  ``datatype`` - (default: None) None, "list", "str", "tuple", "iter",
+       "callable". If None, then the function
+       tries to guess this from the data.
+    -  ``caching`` - (default: True) True or False. Whether to keep a cache
+       of the letters computed by an iterator or callable.
+
+    .. note::
+
+       Be careful when defining words using callables and iterators. It
+       appears that islice does not pickle correctly causing various errors
+       when reloading. Also, most iterators do not support copying and
+       should not support pickling by extension.
+
+    EXAMPLES:
+
+    Empty word::
+
         sage: Word()
         word:
-    
-    1. Finite words from strings.
-    
-    ::
-    
+
+    Word with string::
+
         sage: Word("abbabaab")
         word: abbabaab
-    
-    ::
-    
-        sage: Word("abbabaab", alphabet="abc")
-        word: abbabaab
-    
-    2. Finite words from lists.
-    
-    ::
-    
-        sage: Word(["a", "b", "b", "a", "b", "a", "a", "b"])
-        word: abbabaab
-    
-    ::
-    
-        sage: Word([0,1,1,0,1,0])
-        word: 011010
-    
-    3. Finite words from functions.
-    
-    ::
-    
-        sage: f = lambda n : n % 2
-        sage: Word(f, [0, 1])[:17]
-        word: 01010101010101010
-    
-    4. Finite words from iterators.
-    
-    ::
-    
-        sage: def tmword():
-        ...    thuemorse = WordMorphism('a->ab,b->ba')
-        ...    w = thuemorse('a')[:]
-        ...    i = 0
-        ...    while w:
-        ...        for x in thuemorse(w[i]):
-        ...            yield x
-        ...        else:
-        ...            w *= thuemorse(w[i+1])
-        ...            i += 1
-        sage: Word(tmword(), alphabet="ab")[:32]
-        word: abbabaabbaababbabaababbaabbabaab
-    
-    5. Infinite words from functions.
-    
-    ::
-    
-        sage: f = lambda n : n % 2
-        sage: Word(f, alphabet=[0, 1])
-        Infinite word over [0, 1]
-    
-    6. Infinite words from iterators.
-    
-    ::
-    
-        sage: def tmword():
-        ...    thuemorse = WordMorphism('a->ab,b->ba')
-        ...    w = thuemorse('a')[:]
-        ...    i = 0
-        ...    while w:
-        ...        for x in thuemorse(w[i]):
-        ...            yield x
-        ...        else:
-        ...            w *= thuemorse(w[i+1])
-        ...            i += 1
-        sage: Word(tmword(), alphabet="ab")
-        Infinite word over ['a', 'b']
-    
-    TESTS::
-    
-        sage: f = lambda n : n % 2
+
+    Word with string constructed from other types::
+
+        sage: Word([0,1,1,0,1,0,0,1], datatype="str")
+        word: 01101001
+        sage: Word((0,1,1,0,1,0,0,1), datatype="str")
+        word: 01101001
+
+    Word with list::
+
+        sage: Word([0,1,1,0,1,0,0,1])
+        word: 01101001
+
+    Word with list constructed from other types::
+
+        sage: Word("01101001", datatype="list")
+        word: 01101001
+        sage: Word((0,1,1,0,1,0,0,1), datatype="list")
+        word: 01101001
+
+    Word with tuple::
+
+        sage: Word((0,1,1,0,1,0,0,1))
+        word: 01101001
+
+    Word with tuple constructed from other types::
+
+        sage: Word([0,1,1,0,1,0,0,1], datatype="tuple")
+        word: 01101001
+        sage: Word("01101001", datatype="str")
+        word: 01101001
+
+    Word with iterator::
+
+        sage: from itertools import count
+        sage: Word(count())
+        word: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,...
+        sage: Word(iter("abbabaab")) # iterators default to infinite words
+        word: abbabaab
+        sage: Word(iter("abbabaab"), length="unknown")
+        word: abbabaab
+        sage: Word(iter("abbabaab"), length="finite")
+        word: abbabaab
+
+    Word with function (a 'callable')::
+
+        sage: f = lambda n : add(Integer(n).digits(2)) % 2
         sage: Word(f)
-        Traceback (most recent call last):
-          ...
-        TypeError: alphabet is required for words not defined by lists or strings
-        sage: Word(f, alphabet=[1])
-        Infinite word over [1]
-    """
-    # If the alphabet is not specified, then try to build one from data.
-    if alphabet is None:
-        if data is None:
-            alphabet = []
-        elif isinstance(data, (str,list)):
-            alphabet = sorted(set(data))
-        else:
-            raise TypeError, "alphabet is required for words not defined by lists or strings"
-    # Return the word object
-    return Words(alphabet)(data)
+        word: 0110100110010110100101100110100110010110...
+        sage: Word(f, length=8)
+        word: 01101001
+
+    Word over a string with a parent::
+
+        sage: w = Word("abbabaab", alphabet="abc"); w
+        word: abbabaab
+        sage: w.parent()
+        Words over Ordered Alphabet ['a', 'b', 'c']
+
+    The default parent is the combinatorial class of all words::
+
+        sage: w = Word("abbabaab"); w
+        word: abbabaab
+        sage: w.parent()
+        Words
+    """
+    # TODO: doctest this part!
+    if isinstance(data, Word_class):
+        from words import Words
+        if data.parent() != Words(alphabet):
+            import copy
+            data = copy.copy(data)
+            data._parent = Words(alphabet)
+            data.parent()._check(data)
+        return data
+
+    if data is None:
+        data = []
+
+    # Guess the datatype if it is not given.
+    if datatype is None:
+        if isinstance(data, (list, CombinatorialObject)):
+            datatype = "list"
+        elif isinstance(data, (str)):
+            datatype = "str"
+        elif isinstance(data, tuple):
+            datatype = "tuple"
+        elif callable(data):
+            datatype = "callable"
+        elif hasattr(data,"__iter__"):
+            datatype = "iter"
+        elif isinstance(data, WordContent):
+            # For backwards compatibility (picklejar)
+            return _word_from_word_content(data=data, parent=alphabet)
+        else:
+            raise ValueError, "Cannot guess a datatype; please specify one"
+    else:
+        # type check the datatypes
+        if datatype == "iter" and not hasattr(data, "__iter__"):
+            raise ValueError, "Your data is not iterable"
+        elif datatype == "callable" and not callable(data):
+            raise ValueError, "Your data is not callable"
+        elif datatype not in ("list", "tuple", "str",
+                                "callable", "iter"):
+            raise ValueError, "Unknown datatype"
+
+    # Create the parent object
+    from words import Words
+    parent = Words() if alphabet is None else Words(alphabet)
+
+    # Construct the word
+    if datatype == 'list':
+        w = FiniteWord_list(parent=parent,data=data)
+    elif datatype == 'str':
+        w = FiniteWord_str(parent=parent,data=data)
+    elif datatype == 'tuple':
+        w = FiniteWord_tuple(parent=parent,data=data)
+    elif datatype == 'callable':
+        if caching:
+            if length is None or length is Infinity:
+                cls = InfiniteWord_callable_with_caching
+            else:
+                cls = FiniteWord_callable_with_caching
+        else:
+            if length is None or length is Infinity:
+                cls = InfiniteWord_callable
+            else:
+                cls = FiniteWord_callable
+        w = cls(parent=parent,callable=data,length=length)
+    elif datatype == 'iter':
+        if caching:
+            if length is None or length is Infinity:
+                cls = InfiniteWord_iter_with_caching
+            elif length == 'finite':
+                cls = FiniteWord_iter_with_caching
+            elif length == 'unknown':
+                cls = Word_iter_with_caching
+            elif length in ZZ and length >= 0:
+                cls = FiniteWord_iter_with_caching
+            else:
+                raise ValueError, "not a correct value for length (%s)" % length
+        else:
+            if length is None or length is Infinity:
+                cls = InfiniteWord_iter
+            elif length == 'finite':
+                cls = FiniteWord_iter
+            elif length == 'unknown':
+                cls = Word_iter
+            elif length in ZZ and length >= 0:
+                cls = FiniteWord_iter
+            else:
+                raise ValueError, "not a correct value for length (%s)" % length
+        w = cls(parent=parent,iter=data,length=length)
+    else:
+        raise ValueError, "Not known datatype"
+
+    # Do some minimal checking.
+    w.parent()._check(w)
+    return w
+
+###########################################################################
+##### DEPRECATION WARNINGS ################################################
+##### Added July 2009 #####################################################
+###########################################################################
 
 def is_Word(obj):
     r"""
     Returns True if obj is a word, and False otherwise.
-    
+
     EXAMPLES::
-    
+
         sage: from sage.combinat.words.word import is_Word
         sage: is_Word(33)
+        doctest:1: DeprecationWarning: is_Word is deprecated, use isinstance(your_object, Word_all) instead!
         False
         sage: is_Word(Word('abba'))
         True
     """
-    return isinstance(obj, AbstractWord)
+    from sage.misc.misc import deprecation
+    deprecation("is_Word is deprecated, use isinstance(your_object, Word_all) instead!")
+    return isinstance(obj, Word_class)
 
 def is_FiniteWord(obj):
     r"""
     Returns True if obj is a finite word, and False otherwise.
-    
+
     EXAMPLES::
-    
+
         sage: from sage.combinat.words.word import is_FiniteWord
         sage: is_FiniteWord(33)
+        doctest:1: DeprecationWarning: is_Word is deprecated, use isinstance(your_object, Word_all) instead!
         False
         sage: is_FiniteWord(Word('baab'))
         True
     """
-    if isinstance(obj, AbstractWord) and haslen(obj):
+    from sage.misc.misc import deprecation
+    deprecation("is_Word is deprecated, use isinstance(your_object, Word_all) instead!")
+    if isinstance(obj, Word_class):
+        try:
+            len(obj)
+        except:
+            return False
         return True
     else:
         return False
@@ -313,120 +487,658 @@
 #                                                                     #
 #######################################################################
 
-class AbstractWord(SageObject):
-    def __init__(self, parent, word, mapping=None, format=None, part=slice(None)):
-        r"""
-        Initialize the AbstractWord object with the parent relationship.
-        
-        INPUT:
-        
-        
-        -  ``word`` - a function or an iterable, possibly with
-           a defined length
-        
-        -  ``mapping`` - function, a map sending elements
-           output by word to nonnegative integers. The default is
-           parent.alphabet().rank; that is, the index of the symbol in the
-           alphabet.
-        
-        -  ``format`` - string (default None), the explicit
-           type of word. Can be either 'empty', 'list', 'string', 'function'
-           or 'iterator'. If set to None (the default), an attempt will be
-           made to infer the type from properties of word.
-        
-        -  ``part`` - slice (default slice(None)), the portion
-           of word to use.
-        
-        
-        TESTS::
-        
-            sage: from sage.combinat.words.word import AbstractWord
-            sage: from sage.combinat.words.word_content import BuildWordContent
-            sage: W = Words('abc')
-            sage: content = BuildWordContent('')
-            sage: AbstractWord(W, content)
-            Word
-            sage: AbstractWord(W, AbstractWord(W, content))
-            Word
-            sage: AbstractWord(W, '', format='list')
-            Word
-            sage: AbstractWord(W, lambda n:n, format='function')
-            Word
-            sage: AbstractWord(W, '')
-            Word
-            sage: AbstractWord(33, '')
-            Traceback (most recent call last):
-            ...
-            TypeError: the parent must be an instance of Words
-            sage: g = AbstractWord(W, '')
-            sage: loads(dumps(g))
-            Word
-        """
-        if not is_Words(parent):
-            raise TypeError, "the parent must be an instance of Words"
-        self._parent = parent
-
-        if isinstance(word, AbstractWord):
-            # TODO: Is coercion is necessary here?
-            self._word_content = word._word_content
-        elif is_WordContent(word):
-            # TODO: Is coercion is necessary here?
-            self._word_content = word
-        else:
-            if mapping is None:
-                if hasattr(parent, "alphabet"):
-                    mapping = parent.alphabet().rank
+class Word_class(SageObject):
+    def parent(self):
+        r"""
+        Returns the parent of self.
+        
+        TESTS::
+
+            sage: Word(iter([1,2,3]), length="unknown").parent()
+            Words
+            sage: Word(range(12)).parent()
+            Words
+            sage: Word(range(4), alphabet=range(6)).parent()
+            Words over Ordered Alphabet [0, 1, 2, 3, 4, 5]
+            sage: Word(iter('abac'), alphabet='abc').parent()
+            Words over Ordered Alphabet ['a', 'b', 'c']
+        """
+        return self._parent
+
+    def _repr_(self):
+        r"""
+        Returns a string representation of self.
+        
+        TESTS::
+
+            sage: Word(iter([1,2,3]), length="unknown")._repr_()
+            'word: 123'
+            sage: Word(xrange(100), length="unknown")._repr_()
+            'word: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,...'
+            sage: Word(lambda x:x%3)._repr_()
+            'word: 0120120120120120120120120120120120120120...'
+        """
+        global word_options
+        if word_options['old_repr']:
+            rep = ""
+            if isinstance(self, InfiniteWord_class):
+                return "Infinite word over %s" % (str(self.parent().alphabet())[17:])
+            elif isinstance(self, FiniteWord_class):
+                if word_options['truncate'] and \
+                        self.length() > word_options['truncate_length']:
+                    return "Finite word of length %s over %s" % (self.length(), str(self.parent().alphabet())[17:])
                 else:
-                    mapping = id_f
-            self._word_content = BuildWordContent(word,
-                mapping=mapping, format=format, part=part)
-
-    def size_of_alphabet(self):
-        """
-        Returns the size of the alphabet of the word.
-
-        TESTS::
-        
-            sage: from sage.combinat.words.word import AbstractWord
-            sage: AbstractWord(Words('ab'), '').size_of_alphabet()
-            2
-            sage: AbstractWord(Words('abc'), '').size_of_alphabet()
-            3
-        """
-        return self._parent.size_of_alphabet()
-
-    def _repr_(self):
-        r"""
-        Returns a string representation of self.
-        
-        TESTS::
-        
-            sage: from sage.combinat.words.word import AbstractWord
-            sage: AbstractWord(Words('ab'), '')._repr_()
-            'Word'
-        """
-        return "Word"
-
-    def parent(self):
-        r""" 
-        Returns the parent object from which the word was created.
-        
-        EXAMPLES::
-        
-            sage: from sage.combinat.words.word import AbstractWord
-            sage: W = Words('ab')
-            sage: w = AbstractWord(W, '')
-            sage: w.parent()
-            Words over Ordered Alphabet ['a', 'b']
-            sage: w.parent() is W
-            True
-        """
-        return self._parent
+                    return word_options['identifier'] + self.string_rep()
+            else:
+                return "Word over %s" % (str(self.parent().alphabet())[17:])
+        return word_options['identifier'] + self.string_rep()
+
+    def string_rep(self):
+        r"""
+        Returns the raw sequence of letters as a string.
+        
+        EXAMPLES::
+
+            sage: Word('abbabaab').string_rep()
+            'abbabaab'
+            sage: Word([0, 1, 0, 0, 1]).string_rep()
+            '01001'
+            sage: Word([0,1,10,101]).string_rep()
+            '0,1,10,101'
+            sage: WordOptions(letter_separator='-')
+            sage: Word([0,1,10,101]).string_rep()
+            '0-1-10-101'
+            sage: WordOptions(letter_separator=',')
+        """
+        global word_options
+        l = word_options['truncate_length']
+        letters = list(islice(self, l+1))
+        if len(letters) == l+1:
+            letters.pop()
+            suffix = "..."
+        else:
+            suffix = ""
+        if word_options['display'] == 'string':
+            ls = word_options['letter_separator']
+            letters = map(str, letters)
+            if all(len(a)==1 for a in letters):
+                return ''.join(letters) + suffix
+            elif suffix == "...":
+                return ls.join(letters) + ls + suffix
+            else:
+                return ls.join(letters)
+        elif word_options['display'] == 'list':
+            if suffix == "...":
+                return "[%s, %s]" % (str(list(letters))[1:-1], suffix)
+            else:
+                return str(list(letters))
+
+    def __iter__(self):
+        r"""
+        EXAMPLES::
+
+            sage: from sage.combinat.words.word import Word_class
+            sage: w = Word_class()
+            sage: w.__iter__()
+            Traceback (most recent call last):
+            ...
+            NotImplementedError: you need to define an iterator in __iter__
+        """
+        raise NotImplementedError, "you need to define an iterator in __iter__"
+
+    def length(self):
+        r"""
+        Returns the length of self.
+        
+        TESTS::
+
+            sage: from sage.combinat.words.word import Word_class
+            sage: w = Word(iter('abba'*100), length="unknown")
+            sage: w.length() is None
+            True
+            sage: w = Word(iter('abba'), length="finite")
+            sage: w.length()
+            4
+            sage: w = Word(iter([0,1,1,0,1,0,0,1]*100), length="unknown")
+            sage: w.length() is None
+            True
+            sage: w = Word(iter([0,1,1,0,1,0,0,1]), length="finite")
+            sage: w.length()
+            8
+        """
+        return self._len
+
+    # TODO: deprecate the use of __len__ in a later version
+    __len__ = length
+
+    def __cmp__(self, other):
+        r"""
+        Compares two words lexicographically according to Python's built-in
+        ordering. Provides for all normal comparison operators.
+       
+        NOTE:
+            This function will not terminate if self and other are equal
+            infinite words!
+            
+        EXAMPLES::
+
+            sage: W = Word
+            sage: from itertools import count
+            sage: W(range(1,10)).__cmp__(W(range(10))) > 0
+            True
+            sage: W(range(10)).__cmp__(W(range(1,10))) < 0
+            True
+            sage: W(range(10)).__cmp__(W(range(10))) == 0
+            True
+            sage: W(range(10)).__cmp__(W(count())) < 0
+            True
+            sage: W(count()).__cmp__(W(range(10))) > 0
+            True
+        """
+        if not isinstance(other, Word_class):
+            return NotImplemented
+        self_it, other_it = iter(self), iter(other)
+        cmp_fcn = self._parent.cmp_letters
+        for (c1, c2) in izip(self_it, other_it):
+            r = cmp_fcn(c1,c2)
+            if r != 0:
+                return r
+        else:
+            # If self_it is not exhausted, then other_it must be,
+            # so other is a proper prefix of self. So self > other; 
+            # return 1.
+            try:
+                self_it.next()
+                return 1
+            except StopIteration:
+                # If self_it is exhausted, then we need to check other_it.
+                # If other_it is exhausted also, then self == other. Return
+                # 0. Otherwise, self is a proper prefix of other. 
+                # So self < other; teturn -1.
+                try:
+                    other_it.next()
+                    return -1
+                except StopIteration:
+                    return 0
+
+    def _longest_common_prefix_iterator(self, other):
+        r"""
+        Return an iterator of the longest common prefix of self and other.
+
+        INPUT:
+
+        -  ``other`` - word
+            
+        OUTPUT:
+
+            iterator
+
+        EXAMPLES::
+
+            sage: f = words.FibonacciWord()
+            sage: it = f._longest_common_prefix_iterator(f)
+            sage: w = Word(it, length="unknown"); w
+            word: 0100101001001010010100100101001001010010...
+            sage: w[:6]
+            word: 010010
+            sage: it = w._longest_common_prefix_iterator(w[:10])
+            sage: w = Word(it, length="finite"); w
+            word: 0100101001
+        """
+        for (b,c) in izip(self, other):
+            if b == c:
+                yield b
+            else:
+                raise StopIteration
+        else:
+            raise StopIteration
+
+    def longest_common_prefix(self, other):
+        r"""
+        Returns the longest common prefix of self and other.
+        
+        EXAMPLES::
+
+            sage: f = lambda n : add(Integer(n).digits(2)) % 2
+            sage: t = Word(f); t
+            word: 0110100110010110100101100110100110010110...
+            sage: u = t[:10]; u
+            word: 0110100110
+            sage: w = t.longest_common_prefix(u); w
+            word: 0110100110
+
+        The longest common prefix of two equal infinite words::
+
+            sage: t1 = Word(f); t1
+            word: 0110100110010110100101100110100110010110...
+            sage: t2 = Word(f); t2
+            word: 0110100110010110100101100110100110010110...
+            sage: t1.longest_common_prefix(t2)
+            word: 0110100110010110100101100110100110010110...
+        """
+        if isinstance(other, FiniteWord_class):
+            return other.longest_common_prefix(self)
+        return self._parent(self._longest_common_prefix_iterator(other), length="unknown")
+
+    def is_empty(self):
+        r"""
+        Returns True if the length of self is zero, and False otherwise.
+        
+        EXAMPLES::
+
+            sage: it = iter([])
+            sage: Word(it).is_empty()
+            True
+            sage: it = iter([1,2,3])
+            sage: Word(it).is_empty()
+            False
+            sage: from itertools import count
+            sage: Word(count()).is_empty()
+            False
+        """
+        try:
+            iter(self).next()
+            return False
+        except StopIteration:
+            return True
+
+    def _to_integer_iterator(self):
+        r"""
+        Returns an iterator that iterators over the letters of an integer
+        representation of self. The first letter occurring in self is
+        mapped to zero, and every letter that hasn't yet occurred in the
+        word is mapped to the next available integer.
+
+        EXAMPLES::
+
+            sage: from itertools import count
+            sage: w = Word(count())
+            sage: ir = w._to_integer_iterator()
+            sage: [ir.next() for _ in range(10)]
+            [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+            sage: w = Word(iter("abbacabba"))
+            sage: ir = w._to_integer_iterator()
+            sage: list(ir)
+            [0, 1, 1, 0, 2, 0, 1, 1, 0]
+        """
+        mapping = {}
+        next_value = 0
+        for letter in self:
+            if not(letter in mapping):
+                mapping[letter] = next_value
+                next_value += 1
+            yield mapping[letter]
+
+    def to_integer_word(self):
+        r"""
+        Returns a word over the integers whose letters are those output by
+        self._to_integer_iterator()
+
+        EXAMPLES::
+
+            sage: from itertools import count
+            sage: w = Word(count()); w
+            word: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,...
+            sage: w.to_integer_word()
+            word: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,...
+            sage: w = Word(iter("abbacabba"), length="finite"); w
+            word: abbacabba
+            sage: w.to_integer_word()
+            word: 011020110
+            sage: w = Word(iter("abbacabba"), length="unknown"); w
+            word: abbacabba
+            sage: w.to_integer_word()
+            word: 011020110
+        """
+        length = "unknown" if self._len is None else self._len
+        return Word(self._to_integer_iterator(), length=length)
+
+    def lex_less(self, other):
+        r"""
+        Returns True if self is lexicographically less than other.
+
+        EXAMPLES::
+
+            sage: w = Word([1,2,3])
+            sage: u = Word([1,3,2])
+            sage: v = Word([3,2,1])
+            sage: w.lex_less(u)
+            True
+            sage: v.lex_less(w)
+            False
+            sage: a = Word("abba")
+            sage: b = Word("abbb")
+            sage: a.lex_less(b)
+            True
+            sage: b.lex_less(a)
+            False
+
+        For infinite words::
+
+            sage: t = words.ThueMorseWord()
+            sage: t.lex_less(t[:10])
+            False
+            sage: t[:10].lex_less(t)
+            True
+        """
+        return self < other 
+
+    def lex_greater(self, other):
+        r"""
+        Returns True if self is lexicographically greater than other.
+
+        EXAMPLES::
+
+            sage: w = Word([1,2,3])
+            sage: u = Word([1,3,2])
+            sage: v = Word([3,2,1])
+            sage: w.lex_greater(u)
+            False
+            sage: v.lex_greater(w)
+            True
+            sage: a = Word("abba")
+            sage: b = Word("abbb")
+            sage: a.lex_greater(b)
+            False
+            sage: b.lex_greater(a)
+            True
+
+        For infinite words::
+
+            sage: t = words.ThueMorseWord()
+            sage: t[:10].lex_greater(t)
+            False
+            sage: t.lex_greater(t[:10])
+            True
+        """
+        return self > other 
+
+    def apply_morphism(self,morphism):
+        r"""
+        Returns the word obtained by applying the morphism to self.
+        
+        INPUT:
+
+        -  ``morphism`` - Can be an instance of WordMorphism, or
+           anything that can be used to construct one.
+        
+        EXAMPLES::
+
+            sage: w = Word("ab")
+            sage: d = {'a':'ab', 'b':'ba'}
+            sage: w.apply_morphism(d)
+            word: abba
+            sage: w.apply_morphism(WordMorphism(d))
+            word: abba
+
+        ::
+
+            sage: w = Word('ababa')
+            sage: d = dict(a='ab', b='ba')
+            sage: d
+            {'a': 'ab', 'b': 'ba'}
+            sage: w.apply_morphism(d)
+            word: abbaabbaab
+
+        For infinite words::
+
+            sage: t = words.ThueMorseWord([0,1]); t
+            Thue-Morse word over Ordered Alphabet [0, 1]
+            sage: t.apply_morphism({0:8,1:9})
+            word: 8998988998898998988989988998988998898998...
+        """
+        from sage.combinat.words.morphism import WordMorphism
+        if not isinstance(morphism, WordMorphism):
+            morphism = WordMorphism(morphism)
+        return morphism(self)
+
+    def _delta_iterator(self):
+        r"""
+        Returns an iterator of the image of self under the delta morphism. 
+        This is the word composed of the length of consecutive runs of the 
+        same letter in a given word.
+
+        OUTPUT:
+
+            generator object
+        
+        EXAMPLES::
+
+            sage: W = Words('0123456789')
+            sage: it=W('22112122')._delta_iterator()
+            sage: Word(it)
+            word: 22112
+            sage: Word(W('555008')._delta_iterator())
+            word: 321
+            sage: Word(W()._delta_iterator())
+            word: 
+
+        For infinite words::
+
+            sage: t = words.ThueMorseWord()
+            sage: it = t._delta_iterator()
+            sage: Word(it)
+            word: 1211222112112112221122211222112112112221...
+        """
+        from itertools import groupby
+        for letter, run in groupby(self):
+            yield len(list(run))
+
+    def delta(self):
+        r"""
+        Returns the image of self under the delta morphism. This is the
+        word composed of the length of consecutive runs of the same letter
+        in a given word.
+
+        OUTPUT:
+
+            Word over integers
+        
+        EXAMPLES:
+
+        For finite words::
+
+            sage: W = Words('0123456789')
+            sage: W('22112122').delta()
+            word: 22112
+            sage: W('555008').delta()
+            word: 321
+            sage: W().delta()
+            word: 
+            sage: Word('aabbabaa').delta()
+            word: 22112
+
+        For infinite words::
+
+            sage: t = words.ThueMorseWord()
+            sage: t.delta()
+            word: 1211222112112112221122211222112112112221...
+        """
+        return Word(self._delta_iterator())
+
+    def _iterated_right_palindromic_closure_iterator(self, f=None):
+        r"""
+        Returns an iterator over the iterated (`f`-)palindromic closure of self.
+                            
+        INPUT:
+
+        -  ``f`` - involution (default: None) on the alphabet of self. It must 
+           be callable on letters as well as words (e.g. WordMorphism).
+                             
+        OUTPUT:
+
+            iterator -- the iterated (`f`-)palindromic closure of self
+            
+        EXAMPLES::
+
+            sage: w = Word('abc')
+            sage: it = w._iterated_right_palindromic_closure_iterator()
+            sage: Word(it)
+            word: abacaba
+
+        ::
+
+            sage: w = Word('aaa')
+            sage: it = w._iterated_right_palindromic_closure_iterator()
+            sage: Word(it)
+            word: aaa
+
+        ::
+
+            sage: w = Word('abbab')
+            sage: it = w._iterated_right_palindromic_closure_iterator()
+            sage: Word(it)
+            word: ababaabababaababa
+
+        An infinite word::
+
+            sage: t = words.ThueMorseWord('ab')
+            sage: it = t._iterated_right_palindromic_closure_iterator()
+            sage: Word(it)
+            word: ababaabababaababaabababaababaabababaabab...
+
+        TESTS:
+
+        The empty word::
+
+            sage: w = Word()
+            sage: it = w._iterated_right_palindromic_closure_iterator()
+            sage: it.next()
+            Traceback (most recent call last):
+            ...
+            StopIteration
+
+        REFERENCES:
+
+        -   [1] A. de Luca, A. De Luca, Pseudopalindrome closure operators
+            in free monoids, Theoret. Comput. Sci. 362 (2006) 282--300.      
+        """
+        par = self.parent()
+        w = self[:0]
+        for letter in self:
+            length_before = w.length()
+            w = (w*par([letter])).palindromic_closure(f=f)
+            length_after = w.length()
+            d = length_after - length_before
+            for a in w[-d:]:
+                yield a
+
+    def iterated_right_palindromic_closure(self, f=None):
+        r"""
+        Returns the iterated (`f`-)palindromic closure of self.
+                            
+        INPUT:
+
+        -  ``f`` - involution (default: None) on the alphabet of self. It must 
+           be callable on letters as well as words (e.g. WordMorphism).
+                             
+        OUTPUT:
+
+            word -- the iterated (`f`-)palindromic closure of self
+            
+        EXAMPLES::
+
+            sage: w = Word('abc')
+            sage: w.iterated_right_palindromic_closure()
+            word: abacaba
+
+            sage: w = Word('aaa')
+            sage: w.iterated_right_palindromic_closure()
+            word: aaa
+
+            sage: w = Word('abbab')
+            sage: w.iterated_right_palindromic_closure()
+            word: ababaabababaababa
+
+        An right f-palindromic closure::
+
+            sage: f = WordMorphism('a->b,b->a')
+            sage: w = Word('abbab')
+            sage: w.iterated_right_palindromic_closure(f=f)
+            word: abbaabbaababbaabbaabbaababbaabbaab
+
+        An infinite word::
+
+            sage: t = words.ThueMorseWord('ab')
+            sage: t.iterated_right_palindromic_closure()
+            word: ababaabababaababaabababaababaabababaabab...
+
+        TESTS:
+
+        The empty word::
+
+            sage: w = Word()
+            sage: w.iterated_right_palindromic_closure()
+            word:
+
+        REFERENCES:
+
+        -   A. de Luca, A. De Luca, Pseudopalindrome closure operators
+            in free monoids, Theoret. Comput. Sci. 362 (2006) 282--300.      
+        """
+        return Word(self._iterated_right_palindromic_closure_iterator(f=f), length='unknown')
+
+    @lazy_attribute
+    def _word_content(self):
+        r"""
+        EXAMPLES::
+
+            sage: w = Word('abaccefa')
+            sage: w._word_content
+            doctest:...: DeprecationWarning: _word_content is deprecated! try to_integer_word instead! See the documentation for more information
+            word: 01022340
+        """
+        from sage.misc.misc import deprecation
+        deprecation("_word_content is deprecated! try to_integer_word instead! See the documentation for more information")
+        return self.to_integer_word()
+
+    def alphabet(self):
+        r"""
+        EXAMPLES::
+
+            sage: w = Word('abaccefa')
+            sage: w. alphabet()
+            doctest:1: DeprecationWarning: alphabet() is deprecated, use parent().alphabet() instead
+            Python objects
+            sage: y = Words('456')('64654564')
+            sage: y.alphabet()
+            Ordered Alphabet ['4', '5', '6']
+
+        """
+        from sage.misc.misc import deprecation
+        deprecation("alphabet() is deprecated, use parent().alphabet() instead")
+        return self.parent().alphabet()
+
+class FiniteWord_class(Word_class):
+    def __str__(self):
+        r"""
+        Returns the full string representation of the word.
+        
+        TESTS::
+
+            sage: Word('abc').__str__()
+            'word: abc'
+            sage: Word([0, 1, 0, 0, 1] * 10).__str__()
+            'word: 01001010010100101001010010100101001010010100101001'
+            sage: Word([0,1,10,101]).__str__()
+            'word: 0,1,10,101'
+        """
+        global word_options
+        letters = list(self)
+        if word_options['display'] == 'string':
+            ls = word_options['letter_separator']
+            letters = map(str, letters)
+            if all(len(a)==1 for a in letters):
+                return word_options['identifier'] + ''.join(letters)
+            else:
+                return word_options['identifier'] + ls.join(letters)
+        elif word_options['display'] == 'list':
+            return word_options['identifier'] + str(list(letters))
 
     def coerce(self, other):
         r"""
-        Returns a pair of words with a common parent or raises an
-        exception.
+        Tries to return a pair of words with a common parent; raises an
+        exception if this is not possible.
         
         This function begins by checking if both words have the same
         parent. If this is the case, then no work is done and both words
@@ -446,316 +1158,142 @@
             sage: a, b = w1.coerce(w2)
             sage: a.parent() is b.parent()
             True
-        """
-        if self._parent != other._parent:
+            sage: w1.parent() is w2.parent()
+            False
+        """
+        if self.parent() != other.parent():
             try:
                 other = self.parent()(other)
+                other.parent()._check(other, length=None)
             except:
                 try:
                     self = other.parent()(self)
+                    self.parent()._check(self, length=None)
                 except:
-                    raise TypeError, "no coercion rule between %r and %r" % (self.alphabet(), other.alphabet())
+                    raise TypeError, "no coercion rule between %r and %r" % (self.parent(), other.parent())
         return self, other
 
-    def __len__(self):
-        r"""
-        Returns the length of self.
-        
-        TESTS::
-        
-            sage: from sage.combinat.words.word import AbstractWord
-            sage: w = AbstractWord(Words('ab'), 'abba', mapping='ab'.index)
-            sage: len(w)
-            4
-            sage: w = AbstractWord(Words([0,1]), [0,1,1,0,1,0,0,1])
-            sage: len(w)
-            8
-            sage: w = AbstractWord(Words([0,1]), lambda n:n%2)
-            sage: len(w)
-            Traceback (most recent call last):
-            ...
-            TypeError: an integer is required
-        """
-        return len(self._word_content)
-
-class AbstractFiniteWord(AbstractWord):
-    def _repr_(self):
-        r"""
-        Returns a string representation of self.
-        
-        TESTS::
-        
-            sage: sage.combinat.words.word.AbstractFiniteWord(Words('ab'), sage.combinat.words.word_content.BuildWordContent(''))._repr_()
-            'Finite Word'
-        """
-        return "Finite Word"
-
-class AbstractInfiniteWord(AbstractWord):
-    def _repr_(self):
-        r"""
-        Returns a string representation of self.
-        
-        TESTS::
-        
-            sage: sage.combinat.words.word.AbstractInfiniteWord(Words('ab'), sage.combinat.words.word_content.BuildWordContent(''))._repr_()
-            'Infinite Word'
-        """
-        return "Infinite Word"
-
-class Word_over_Alphabet(AbstractWord):
-    def __init__(self, parent, *args, **kwds):
-        r"""
-        Create an Word_over_Alphabet object.
-        
-        INPUT:
-        
-        
-        -  ``parent`` - a parent object inheriting from
-           Words_all that has the alphabet attribute defined
-        
-        -  ``*args, **kwds`` - arguments accepted by
-           AbstractWord
-        
-        
-        EXAMPLES::
-        
-            sage: from sage.combinat.words.word import Word_over_Alphabet
-            sage: W = Words('abc')
-            sage: Word_over_Alphabet(W, "abba")
-            Word over Ordered Alphabet ['a', 'b', 'c']
-        
-        ::
-        
-            sage: from sage.combinat.words.words import Words_all
-            sage: W = Words_all()
-            sage: W.alphabet = lambda : Alphabet("ab")
-            sage: Word_over_Alphabet(W, "abba")
-            Word over Ordered Alphabet ['a', 'b']
-        
-        TESTS::
-        
-            sage: from sage.combinat.words.word import Word_over_Alphabet
-            sage: W = Words('abc')
-            sage: g = Word_over_Alphabet(W, "abba")
-            sage: loads(dumps(g))
-            Word over Ordered Alphabet ['a', 'b', 'c']
-        """
-        if not hasattr(parent, "alphabet"):
-            raise TypeError, "parent object has no alphabet attribute"
-        super(Word_over_Alphabet, self).__init__(parent, *args, **kwds)
-
-    def alphabet(self):
-        r"""
-        Returns the alphabet of the parent.
-        
-        EXAMPLES::
-        
-            sage: Words('abc')('abbabaab').alphabet()
-            Ordered Alphabet ['a', 'b', 'c']
-        """
-        return self._parent.alphabet()
-
-    def _repr_(self):
-        r"""
-        Returns a string representation of self.
-        
-        TESTS::
-        
-            sage: sage.combinat.words.word.Word_over_Alphabet(Words([0,1]), sage.combinat.words.word_content.BuildWordContent([]))._repr_()
-            'Word over Ordered Alphabet [0, 1]'
-        """
-        return "Word over %s" % self.alphabet()
-
-    def __iter__(self):
-        r"""
-        Returns an iterator over the letters of self.
-        
-        EXAMPLES::
-        
-            sage: W = Words('ab')
-            sage: w = W('abba')
-            sage: list(w)           # indirect test
-            ['a', 'b', 'b', 'a']
-        """
-        return imap(self.alphabet().unrank, self._word_content)
-
-    def __getitem__(self, key):
-        r"""
-        TESTS::
-        
-            sage: w = Words('012345')('012345')
-            sage: w[:]
-            word: 012345
-            sage: w[3]
-            '3'
-        """
-        res = self._word_content[key]
-        if is_WordContent(res):
-            return self.parent()(res, format='content')
-        else:
-            return self.alphabet().unrank(res)
-
-class Word_over_OrderedAlphabet(Word_over_Alphabet):
-    def __init__(self, parent, *args, **kwds):
-        r"""
-        Create an Word_over_OrderedAlphabet object.
-        
-        INPUT:
-        
-        
-        -  ``parent`` - a parent object inheriting from
-           Words_all that has the alphabet attribute defined which returns an
-           instance of an OrderedAlphabet_class
-        
-        -  ``*args, **kwds`` - arguments accepted by
-           AbstractWord
-        
-        
-        EXAMPLES::
-        
-            sage: from sage.combinat.words.word import Word_over_OrderedAlphabet
-            sage: W = Words('abc')
-            sage: Word_over_OrderedAlphabet(W, "abba")
-            Word over Ordered Alphabet ['a', 'b', 'c']
-        
-        ::
-        
-            sage: from sage.combinat.words.words import Words_all
-            sage: W = Words_all()
-            sage: W.alphabet = lambda : Alphabet("ab")
-            sage: Word_over_OrderedAlphabet(W, "abba")
-            Word over Ordered Alphabet ['a', 'b']
-        
-        TESTS::
-        
-            sage: from sage.combinat.words.word import Word_over_OrderedAlphabet
-            sage: W = Words('abc')
-            sage: g = Word_over_OrderedAlphabet(W, "abba")
-            sage: loads(dumps(g))
-            Word over Ordered Alphabet ['a', 'b', 'c']
-        """
-        if not hasattr(parent, "alphabet"):
-            raise TypeError, "parent object has no alphabet attribute"
-        if not isinstance(parent.alphabet(), OrderedAlphabet_class):
-            raise TypeError, "underlying alphabet must be an OrderedAlphabet_class"
-        super(Word_over_OrderedAlphabet, self).__init__(parent, *args, **kwds)
-
-#######################################################################
-#                                                                     #
-#                          Infinite words                             #
-#                                                                     #
-#######################################################################
-
-class InfiniteWord_over_Alphabet(AbstractInfiniteWord, Word_over_Alphabet):
-    def _repr_(self):
-        r"""
-        Returns a string representation of self.
-        
-        TESTS::
-        
-            sage: Words([0, 1])(lambda n: n%2)._repr_()
-            'Infinite word over [0, 1]'
-        """
-        return "Infinite word over %s" % self.alphabet().string_rep()
-
-class InfiniteWord_over_OrderedAlphabet(InfiniteWord_over_Alphabet, Word_over_OrderedAlphabet):
-    pass
-
-#######################################################################
-#                                                                     #
-#                           Finite words                              #
-#                                                                     #
-#######################################################################
-
-class FiniteWord_over_Alphabet(AbstractFiniteWord, Word_over_Alphabet):
-    def _repr_(self):
-        r"""
-        Returns a string representation of self.
-        
-        TESTS::
-        
-            sage: from sage.combinat.words.word import FiniteWord_over_Alphabet
-            sage: FiniteWord_over_Alphabet(Words("ab"), "abba")._repr_()
-            "Finite word of length 4 over Ordered Alphabet ['a', 'b']"
-        """
-        return "Finite word of length %s over %s" % (len(self), self.alphabet())
-
-class FiniteWord_over_OrderedAlphabet(FiniteWord_over_Alphabet, Word_over_OrderedAlphabet):
-    def __init__(self, parent, *args, **kwds):
-        r"""
-        TESTS::
-        
-            sage: sage.combinat.words.word.FiniteWord_over_OrderedAlphabet(Words('abcd'), sage.combinat.words.word_content.BuildWordContent('0123', int))
-            word: abcd
-        """
-        super(FiniteWord_over_OrderedAlphabet, self).__init__(parent, *args, **kwds)
-        self._hash = None
-
-    def _repr_(self):
-        r"""
-        Returns a string representation of self.
-        
-        TESTS::
-        
-            sage: from sage.combinat.words.word import FiniteWord_over_OrderedAlphabet
-            sage: mapping = lambda x : "abc".index(x)
-            sage: w = FiniteWord_over_OrderedAlphabet(Words('abc'), 'cabc', mapping=mapping)
-            sage: w._repr_()
-            'word: cabc'
-            sage: Word([0, 1, 0, 1, 1] * 10)._repr_()
-            'Finite word of length 50 over [0, 1]'
-        """
-        global word_options
-        if word_options['truncate'] and len(self) > word_options['truncate_length']:
-            return "Finite word of length %s over %s" % (len(self), self.alphabet().string_rep())
-        else:
-            return str(self)
-
-    def __mul__(self, other):
-        r"""
-        Concatenates two words.
-        
-        EXAMPLES::
-        
-            sage: W = Words([0, 1])
-            sage: W() * W(lambda x:x%2, slice(3))
-            word: 010
-            sage: Words([0, 1, 2])(lambda x:x%3, slice(3)) * Words('01234')('01234')
-            Traceback (most recent call last):
-            ...
-            TypeError: no coercion rule between Ordered Alphabet [0, 1, 2] and Ordered Alphabet ['0', '1', '2', '3', '4']
-        """
-        self, other = self.coerce(other)
-        c = self._word_content.concatenate(other._word_content)
-        return self.parent()(c, format='content')
-
-    __add__ = __mul__
-
+    def __cmp__(self, other):
+        r"""
+        Compares two finite words lexicographically according to Python's
+        built-in ordering. Provides for all normal comparison operators.
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('123').__cmp__(W('1211')) > 0
+            True
+            sage: W('2111').__cmp__(W('12')) > 0
+            True
+            sage: W('123').__cmp__(W('123')) == 0
+            True
+            sage: W('121').__cmp__(W('121')) == 0
+            True
+            sage: W('123').__cmp__(W('22')) < 0
+            True
+            sage: W('122').__cmp__(W('32')) < 0
+            True
+            sage: W([1,1,1]).__cmp__(W([1,1,1,1,1])) < 0
+            True
+            sage: W([1,1,1,1,1]).__cmp__(W([1,1,1])) > 0
+            True
+        """
+        if isinstance(other, type(self)):
+            try:
+                self, other = self.coerce(other)
+            except TypeError:
+                return NotImplemented
+            cmp_fcn = self._parent.cmp_letters
+            for (c1, c2) in izip(self, other):
+                r = cmp_fcn(c1,c2)
+                if r != 0:
+                    return r
+            return self.length() - other.length()
+        else:
+            # for infinite words, use a super __cmp__.
+            return super(FiniteWord_class, self).__cmp__(other)
+
+    def __hash__(self):
+        r"""
+        Returns the hash for this word.
+        
+        TESTS::
+
+             sage: h = hash(Word('abc'))    # indirect test
+             sage: Word('abc').__hash__() == Word('abc').__hash__()
+             True
+        """
+        if self._hash is None:
+            res = 5381
+            for s in self._to_integer_iterator():
+                res = ((res << 5) + res) + s
+            self._hash = res
+        return self._hash
+
+    def concatenate(self, other):
+        r"""
+        Returns the concatenation of self and other.
+
+        INPUT:
+
+        - ``other`` - a word over the same alphabet as self
+
+        EXAMPLES:
+
+        Concatenation may be made using ``+`` or ``*`` operations::
+
+            sage: w = Word('abadafd')
+            sage: y = Word([5,3,5,8,7])
+            sage: w * y
+            word: abadafd53587
+            sage: w + y
+            word: abadafd53587
+            sage: w.concatenate(y)
+            word: abadafd53587
+
+        Both words must be defined over the same alphabet::
+
+            sage: z = Word('12223', alphabet = '123')
+            sage: z + y
+            Traceback (most recent call last):
+            ...
+            ValueError: 5 not in alphabet!
+
+        Eventually, it should work::
+
+            sage: z = Word('12223', alphabet = '123')
+            sage: z + y                   #todo: not implemented
+            word: 1222353587
+        """
+        f = CallableFromListOfWords([self,other])
+        length = self.length() + other.length()
+        return self._parent(f, length=length, datatype='callable', caching=True)
+
+    __mul__ = concatenate
+
+    __add__ = concatenate
+
+    # TODO: This function is using domain=range(n) for Word but
+    # should be a domain=slice(n) # Seb : Feb 23th : I think this is fine now!!
     def __pow__(self, exp):
         r"""
         Return the `exp`-th power of self.
-        
-        If `exp` is `\infty`, returns the infinite periodic
-        word of base self. Otherwise, `|w|\cdot exp` must be an
-        non-negative integer.
-        
-        INPUT:
-        
-        
-        -  ``exp`` - an integer, a rational, a float number or
-           plus infinity.
-        
-        
-        OUTPUT:
-        
-        
-        -  ``word`` - the exp-th power of self.
-        
-        
+
+        If `exp` is `\infty`, returns the infinite periodic word of base self.
+        Otherwise, `|w|\cdot exp` must be an non-negative integer.
+
+        INPUT:
+
+        -  ``exp``  - an integer, a rational, a float number or plus infinity.
+
+        OUTPUT:
+
+            word -- the exp-th power of self.
+                
         EXAMPLES:
-        
+
         You can take non-negative integer powers::
-        
+
             sage: w = Word(range(6)); w
             word: 012345
             sage: w^2
@@ -767,10 +1305,11 @@
             sage: w^(-1)
             Traceback (most recent call last):
             ...
-            ValueError: The exponent must be non-negative.
-        
+            ValueError: Power of the word is not defined on the exponent -1: the length of the word (6) times the exponent (-1) must be a positive integer
+
+
         You can take non-negative rational powers::
-        
+
             sage: w = Word(range(6)); w
             word: 012345
             sage: w^(.5)
@@ -781,214 +1320,160 @@
             True
             sage: w^(5/2)
             word: 012345012345012
-        
-        ...but the length of the word times the exponent must be an
-        integer::
-        
+            
+        ...but the length of the word times the exponent must be an integer::
+
             sage: w = Word(range(6))
             sage: w^(1/4)
             Traceback (most recent call last):
             ...
             ValueError: Power of the word is not defined on the exponent 1/4: the length of the word (6) times the exponent (1/4) must be a positive integer
-        
+            
         You can take infinite power::
-        
+
             sage: w = Word(range(6)); w
             word: 012345
-            sage: w^oo
-            Infinite word over [0, 1, 2, 3, 4, 5]
-            sage: (w^oo)[10000000:20000000]                         
-            Finite word of length 10000000 over [0, 1, 2, 3, 4, 5]
-            sage: (w^oo)[10000000:10000020]
+            sage: u = w^oo; u
+            word: 0123450123450123450123450123450123450123...
+            sage: u[10000000:20000000]                         
+            word: 4501234501234501234501234501234501234501...
+            sage: u[10000000:10000020]
             word: 45012345012345012345
             sage: Word()^oo
-            word:
-        """
-        if exp is infinity:
-            if self.is_empty():
-                return self
-            else:
-                return self.parent()(lambda n: self[n % len(self)])
-        
-        nbCaracteres = len(self)*exp
-        
+            word: 
+        """
+        # powers of the empty word
+        if self.is_empty():
+            return self
+
+        # infinite power of a non-empty word
+        fcn = lambda n: self[n % self.length()]
+        if exp is Infinity:
+            return self._parent(fcn, length=Infinity)
+
         #If exp*|self| is not an integer
-        if int(nbCaracteres) != nbCaracteres :
+        length = exp* self.length()
+        if length in ZZ and length >= 0:
+            return self._parent(fcn, length=length)
+        else:
             raise ValueError, "Power of the word is not defined on the \
 exponent %s: the length of the word (%s) times the exponent \
-(%s) must be a positive integer"  % (exp, len(self), exp)
-
-        #If exp is negative
-        elif exp < 0 :
-            raise ValueError, "The exponent must be non-negative."
-        
-        return self.parent()(lambda n: self[n % len(self)], part=slice(int(nbCaracteres)) )
-        
-    def __str__(self):
-        r"""
-        Returns the full string representation of the word.
-        
-        TESTS::
-        
-            sage: Word('abc').__str__()
-            'word: abc'
-            sage: Words([0, 1])([0, 1, 0, 0, 1] * 10).__str__()
-            'word: 01001010010100101001010010100101001010010100101001'
-            sage: Words(range(1000))([0,1,10,101]).__str__()
-            'word: 0,1,10,101'
-        """
-        global word_options
-        return word_options['identifier'] + self.string_rep()
-
-    def string_rep(self):
-        r"""
-        Returns the raw sequence of letters as a string.
-        
-        EXAMPLES::
-        
-            sage: Words('ab')('abbabaab').string_rep()
-            'abbabaab'
-            sage: Words(range(2))([0, 1, 0, 0, 1]).string_rep()
-            '01001'
-            sage: Words(range(1000))([0,1,10,101]).string_rep()
-            '0,1,10,101'
-            sage: WordOptions(letter_separator='-')
-            sage: Words(range(1000))([0,1,10,101]).string_rep()
-            '0-1-10-101'
-        """
-        global word_options
-        if word_options['display'] == 'string':
-            ls = word_options['letter_separator']
-            letters = map(str, list(self))
-            if all(len(a)==1 for a in letters):
-                return ''.join(letters)
-            else:
-                return ls.join(letters)
-        elif word_options['display'] == 'list':
-            return str(list(self))
-
-    def __cmp__(self, other):
-        """
-        Compares two words lexicographically according to the order defined
-        in the common alphabet. Provides for all normal comparison
-        operators.
-        
-        EXAMPLES::
-        
-            sage: W1 = Words('12'); W2 = Words('123')
-            sage: W2('123').__cmp__(W1('1211')) > 0
-            True
-            sage: W1('2111').__cmp__(W2('12')) > 0
-            True
-            sage: W2('123').__cmp__(W2('123')) == 0
-            True
-            sage: W1('121').__cmp__(W2('121')) == 0
-            True
-            sage: W2('123').__cmp__(W1('22')) < 0
-            True
-            sage: W1('122').__cmp__(W2('32')) < 0
-            True
-            sage: W1('122').__cmp__(Words('ab')('abba'))  # todo: not implemented
-            Traceback (most recent call last):
-            ...
-            TypeError: no coercion rule between Alphabet: ['1', '2'] and Alphabet: ['a', 'b']
-        """
-        if not is_Word(other):
-            return NotImplemented
-        try:
-            self, other = self.coerce(other)
-        except TypeError:
-            return NotImplemented
-        for (c1, c2) in izip(self._word_content, other._word_content):
-            r = c1 - c2
-            if r != 0: return r
-        return len(self) - len(other)
-
-    def __hash__(self):
-        r"""
-        Returns the hash for this word.
-        
-        TESTS::
-        
-            sage: h = hash(Word('abc'))    # indirect test
-            sage: Word('abc').__hash__() == Word('abc').__hash__()
-            True
-        """
-        if self._hash is None:
-            res = 5381
-            for s in self._word_content:
-                res = ((res << 5) + res) + s
-            self._hash = res
-        return self._hash
-        
+(%s) must be a positive integer"  % (exp, self.length(), exp)
+        
+    def length(self):
+        r"""
+        Returns the length of self.
+        
+        TESTS::
+
+            sage: from sage.combinat.words.word import Word_class
+            sage: w = Word(iter('abba'*40), length="finite")
+            sage: w._len is None
+            True
+            sage: w.length()
+            160
+            sage: w = Word(iter('abba'), length=4)
+            sage: w._len
+            4
+            sage: w.length()
+            4
+            sage: def f(n):
+            ...     return range(2,12,2)[n]
+            sage: w = Word(f, length=5)
+            sage: w.length()
+            5
+        """
+        if self._len is None:
+            self._len = Integer(sum(1 for _ in self))
+        return self._len
+
     def is_empty(self):
-        """
+        r"""
         Returns True if the length of self is zero, and False otherwise.
         
         EXAMPLES::
-        
-            sage: W=Words('ab')
-            sage: W().is_empty()
-            True
-            sage: W('a').is_empty()
-            False
-        """
-        return len(self)==0
-
-    def is_prefix_of(self, other):
-        """
-        Returns True if self is a prefix of other, and False otherwise.
-        
-        EXAMPLES::
-        
-            sage: V = Words('0123456789')
-            sage: w = V('0123456789')
-            sage: y = V('012345')
-            sage: y.is_prefix_of(w)
-            True
-            sage: w.is_prefix_of(y) 
-            False
-            sage: W = Words('ab')
-            sage: w.is_prefix_of(W())
-            False
-            sage: W().is_prefix_of(w)
-            True
-            sage: W().is_prefix_of(W())
-            True
-        """
-        return self == other[:len(self)]
-
-    def is_proper_prefix_of(self, other):
-        """
-        Returns True if self is a proper prefix of other, and False
-        otherwise.
-        
-        EXAMPLES::
-        
-            sage: W = Words('123')
-            sage: W('12').is_proper_prefix_of(W('123'))
-            True
-            sage: W('12').is_proper_prefix_of(W('12'))
-            False
-            sage: W().is_proper_prefix_of(W('123'))
-            True
-            sage: W('123').is_proper_prefix_of(W('12'))
-            False
-            sage: W().is_proper_prefix_of(W())
-            False
-        """
-        return self.is_prefix_of(other) and len(self) < len(other)
-
+
+            sage: Word([]).is_empty()
+            True
+            sage: Word('a').is_empty()
+            False
+        """
+        return self.length()==0
+
+    def to_integer_word(self):
+        r"""
+        Returns a word defined over the integers [0,1,...,self.length()-1]
+        whose letters are in the same relative order in the parent.
+
+        EXAMPLES::
+
+            sage: from itertools import count
+            sage: w = Word('abbabaab')
+            sage: w.to_integer_word()
+            word: 01101001
+            sage: w = Word(iter("cacao"), length="finite")
+            sage: w.to_integer_word()
+            word: 10102
+            sage: w = Words([3,2,1])([2,3,3,1])
+            sage: w.to_integer_word()
+            word: 1002
+        """
+        return Word(self.to_integer_list())
+
+    def to_integer_list(self):
+        r"""
+        Returns a list of integers from [0,1,...,self.length()-1] in the
+        same relative order as the letters in self in the parent.
+
+        EXAMPLES::
+
+            sage: from itertools import count
+            sage: w = Word('abbabaab')
+            sage: w.to_integer_list()
+            [0, 1, 1, 0, 1, 0, 0, 1]
+            sage: w = Word(iter("cacao"), length="finite")
+            sage: w.to_integer_list()
+            [1, 0, 1, 0, 2]
+            sage: w = Words([3,2,1])([2,3,3,1])
+            sage: w.to_integer_list()
+            [1, 0, 0, 2]
+        """
+        cmp_fcn = self._parent.cmp_letters
+        ordered_alphabet = sorted(set(self), cmp=cmp_fcn)
+        index = dict((b,a) for (a,b) in enumerate(ordered_alphabet))
+        return [index[a] for a in self]
+
+    def size_of_alphabet(self):
+        r"""
+        EXAMPLES::
+
+            sage: w = Word('abaccefa')
+            sage: w.size_of_alphabet()
+            doctest:1: DeprecationWarning: size_of_alphabet() is deprecated, use parent().size_of_alphabet() instead!
+            +Infinity
+            sage: y = Words('456')('64654564')
+            sage: y.size_of_alphabet()
+            3
+        """
+        from sage.misc.misc import deprecation
+        deprecation("size_of_alphabet() is deprecated, use parent().size_of_alphabet() instead!")
+        return self.parent().size_of_alphabet()
+
+    ###########################################################################
+    ##### DEPRECATION WARNINGS (next 4 functions) #############################
+    ##### Added July 2009 #####################################################
+    ###########################################################################
     def is_suffix_of(self, other):
-        """
+        r"""
         Returns True if w is a suffix of other, and False otherwise.
         
         EXAMPLES::
-        
-            sage: W = Words('0123456789')
+
+            sage: W = Word
             sage: w = W('0123456789')
             sage: y = W('56789')
             sage: y.is_suffix_of(w)
+            doctest:1: DeprecationWarning: is_suffix_of is deprecated, use is_suffix instead!
             True
             sage: w.is_suffix_of(y)
             False
@@ -1001,17 +1486,20 @@
             sage: W().is_suffix_of(W())
             True
         """
-        return self.is_empty() or self == other[-len(self):]
+        from sage.misc.misc import deprecation
+        deprecation("is_suffix_of is deprecated, use is_suffix instead!")
+        return self.is_suffix(other)
 
     def is_proper_suffix_of(self, other):
-        """
-        Returns True if self is a proper suffix of other, and False
-        otherwise.
-        
-        EXAMPLES::
-        
-            sage: W = Words('0123456789')
+        r"""
+        Returns True if self is a proper suffix of other, and False otherwise.
+        
+        EXAMPLES::
+
+            sage: W = Word
             sage: W('23').is_proper_suffix_of(W('123'))
+            doctest:1: DeprecationWarning: is_proper_suffix_of is deprecated, use is_proper_suffix instead!
+            doctest:...: DeprecationWarning: is_suffix_of is deprecated, use is_suffix instead!
             True
             sage: W('12').is_proper_suffix_of(W('12'))
             False
@@ -1020,59 +1508,786 @@
             sage: W('123').is_proper_suffix_of(W('12'))
             False
         """
-        return self.is_suffix_of(other) and len(self) < len(other)
+        from sage.misc.misc import deprecation
+        deprecation("is_proper_suffix_of is deprecated, use is_proper_suffix instead!")
+        return self.is_proper_suffix(other)
+
+    def is_prefix_of(self, other):
+        r"""
+        Returns True if self is a prefix of other, and False otherwise.
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: w = W('0123456789')
+            sage: y = W('012345')
+            sage: y.is_prefix_of(w)
+            doctest:1: DeprecationWarning: is_prefix_of is deprecated, use is_prefix instead!
+            True
+            sage: w.is_prefix_of(y) 
+            False
+            sage: w.is_prefix_of(W())
+            False
+            sage: W().is_prefix_of(w)
+            True
+            sage: W().is_prefix_of(W())
+            True
+        """
+        from sage.misc.misc import deprecation
+        deprecation("is_prefix_of is deprecated, use is_prefix instead!")
+        return self.is_prefix(other)
+
+    def is_proper_prefix_of(self, other):
+        r"""
+        Returns True if self is a proper prefix of other, and False otherwise.
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('12').is_proper_prefix_of(W('123'))
+            doctest:1: DeprecationWarning: is_proper_prefix_of is deprecated, use is_proper_prefix instead!
+            doctest:...: DeprecationWarning: is_prefix_of is deprecated, use is_prefix instead!
+            True
+            sage: W('12').is_proper_prefix_of(W('12'))
+            False
+            sage: W().is_proper_prefix_of(W('123'))
+            True
+            sage: W('123').is_proper_prefix_of(W('12'))
+            False
+            sage: W().is_proper_prefix_of(W())
+            False
+        """
+        from sage.misc.misc import deprecation
+        deprecation("is_proper_prefix_of is deprecated, use is_proper_prefix instead!")
+        return self.is_proper_prefix(other)
+
+    # To fix : do not slice here ! (quite expensive in copy)
+    def is_suffix(self, other):
+        r"""
+        Returns True if w is a suffix of other, and False otherwise.
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: w = W('0123456789')
+            sage: y = W('56789')
+            sage: y.is_suffix(w)
+            True
+            sage: w.is_suffix(y)
+            False
+            sage: W('579').is_suffix(w)
+            False
+            sage: W().is_suffix(y)
+            True
+            sage: w.is_suffix(W())    
+            False
+            sage: W().is_suffix(W())
+            True
+        """
+        return self.is_empty() or self == other[-self.length():]
+
+    def is_proper_suffix(self, other):
+        r"""
+        Returns True if self is a proper suffix of other, and False otherwise.
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('23').is_proper_suffix(W('123'))
+            True
+            sage: W('12').is_proper_suffix(W('12'))
+            False
+            sage: W().is_proper_suffix(W('123'))
+            True
+            sage: W('123').is_proper_suffix(W('12'))
+            False
+        """
+        return self.is_suffix_of(other) and self.length() < other.length()
+
+    def has_suffix(self, other):
+        """
+        Test whether ``self`` has ``other`` as a suffix.
+
+        .. note::
+
+           Some word datatype classes, like :class:`WordDatatype_str`,
+           override this method.
+
+        INPUT::
+
+            - ``other`` - a word, or data describing a word
+
+        OUTPUT::
+
+            - boolean
+         
+        EXAMPLES::
+
+            sage: w = Word("abbabaabababa")
+            sage: u = Word("ababa")
+            sage: w.has_suffix(u)
+            True
+            sage: u.has_suffix(w)
+            False
+            sage: u.has_suffix("ababa")
+            True
+
+        ::
+
+            sage: w = Word([0,1,1,0,1,0,0,1,0,1,0,1,0])
+            sage: u = Word([0,1,0,1,0])
+            sage: w.has_suffix(u)
+            True
+            sage: u.has_suffix(w)
+            False
+            sage: u.has_suffix([0,1,0,1,0])
+            True
+
+        """
+        w = Word(other)
+        return w.is_suffix(self)
+
+    def is_prefix(self, other):
+        r"""
+        Returns True if self is a prefix of other, and False otherwise.
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: w = W('0123456789')
+            sage: y = W('012345')
+            sage: y.is_prefix(w)
+            True
+            sage: w.is_prefix(y) 
+            False
+            sage: w.is_prefix(W())
+            False
+            sage: W().is_prefix(w)
+            True
+            sage: W().is_prefix(W())
+            True
+        """
+        return self == other[:self.length()]
+
+    def is_proper_prefix(self, other):
+        r"""
+        Returns True if self is a proper prefix of other, and False otherwise.
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('12').is_proper_prefix(W('123'))
+            True
+            sage: W('12').is_proper_prefix(W('12'))
+            False
+            sage: W().is_proper_prefix(W('123'))
+            True
+            sage: W('123').is_proper_prefix(W('12'))
+            False
+            sage: W().is_proper_prefix(W())
+            False
+        """
+        return self.is_prefix_of(other) and self.length() < other.length()
+
+    def has_prefix(self, other):
+        r"""
+        Test whether ``self`` has ``other`` as a prefix.
+
+        INPUT::
+
+            - ``other`` - a word, or data describing a word
+
+        OUTPUT::
+
+            - boolean
+         
+        EXAMPLES::
+
+            sage: w = Word("abbabaabababa")
+            sage: u = Word("abbab")
+            sage: w.has_prefix(u)
+            True
+            sage: u.has_prefix(w)
+            False
+            sage: u.has_prefix("abbab")
+            True
+
+        ::
+
+            sage: w = Word([0,1,1,0,1,0,0,1,0,1,0,1,0])
+            sage: u = Word([0,1,1,0,1])
+            sage: w.has_prefix(u)
+            True
+            sage: u.has_prefix(w)
+            False
+            sage: u.has_prefix([0,1,1,0,1])
+            True
+
+
+        """
+        w = Word(other)
+        return w.is_prefix(self)
 
     def reversal(self):
-        """
+        r"""
         Returns the reversal of self.
         
         EXAMPLES::
-        
-            sage: W = Words('0123456789')
+
+            sage: W = Word
             sage: W('124563').reversal()
             word: 365421
         """
         return self[::-1]
 
+    def prefix_function_table(self):
+        r"""
+        Returns a vector containing the length of the proper prefix-suffixes
+        for all the non-empty prefixes of self.
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('121321').prefix_function_table()
+            [0, 0, 1, 0, 0, 1]
+            sage: W('1241245').prefix_function_table()
+            [0, 0, 0, 1, 2, 3, 0]
+            sage: W().prefix_function_table()
+            []
+        """
+        k = 0
+        res = [0]*self.length()
+        for q in xrange(1, self.length()):
+            while k > 0 and self[k] != self[q]:
+                k = res[k-1]
+            if self[k] == self[q]:
+                k += 1
+            res[q] = k
+        return res
+
+    def good_suffix_table(self):
+        r"""
+        Returns a table of the maximum skip you can do in order not to miss
+        a possible occurrence of self in a word.
+        
+        This is a part of the Boyer-Moore algorithm to find factors. See [1].
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('121321').good_suffix_table()
+            [5, 5, 5, 5, 3, 3, 1]
+            sage: W('12412').good_suffix_table()
+            [3, 3, 3, 3, 3, 1]
+            
+        REFERENCES:
+
+        -   [1] R.S. Boyer, J.S. Moore, A fast string searching algorithm,
+            Communications of the ACM 20 (1977) 762--772.
+        """
+        l = self.length()
+        p = self.reversal().prefix_function_table()
+        res = [l - p[-1]]*(l+1)
+        for i in xrange(1, l+1):
+            j = l - p[i - 1]
+            if res[j] > (i - p[i-1]):
+                res[j] = i - p[i-1]
+        return res
+
+    def suffix_trie(self):
+        r"""
+        Returns the suffix trie of self.
+        
+        The *suffix trie* of a finite word `w` is a data structure
+        representing the factors of `w`. It is a tree whose edges are
+        labelled with letters of `w`, and whose leafs correspond to
+        suffixes of `w`.
+        
+        See sage.combinat.words.suffix_trees.SuffixTrie? for more information.
+        
+        EXAMPLES::
+
+            sage: w = Word("cacao")
+            sage: w.suffix_trie()                   # not implemented
+            Suffix Trie of the word: cacao
+
+        ::
+
+            sage: w = Word([0,1,0,1,1])
+            sage: w.suffix_trie()                   # not implemented
+            Suffix Trie of the word: 01011
+        """
+        from sage.combinat.words.suffix_trees import SuffixTrie
+        return SuffixTrie(self)
+
+    def implicit_suffix_tree(self):
+        r"""
+        Returns the implicit suffix tree of self.
+        
+        The *suffix tree* of a word `w` is a compactification of the 
+        suffix trie for `w`. The compactification removes all nodes that have 
+        exactly one incoming edge and exactly one outgoing edge. It consists of
+        two components: a tree and a word. Thus, instead of labelling the edges
+        by factors of `w`, we can labelled them by indices of the occurrence of 
+        the factors in `w`.
+            
+        See sage.combinat.words.suffix_trees.ImplicitSuffixTree? for more information.
+        
+        EXAMPLES::
+
+            sage: w = Word("cacao")
+            sage: w.implicit_suffix_tree()          # not implemented
+            Implicit Suffix Tree of the word: cacao
+            
+        ::
+
+            sage: w = Word([0,1,0,1,1])
+            sage: w.implicit_suffix_tree()          # not implemented
+            Implicit Suffix Tree of the word: 01011
+        """
+        from sage.combinat.words.suffix_trees import ImplicitSuffixTree
+        return ImplicitSuffixTree(self)
+
+    def suffix_tree(self):
+        r"""
+        Alias for implicit_suffix_tree().
+        
+        EXAMPLES::
+
+            sage: Word('abbabaab').suffix_tree() # not implemented
+            Implicit Suffix Tree of the word: abbabaab
+        """
+        return self.implicit_suffix_tree()
+
+    def number_of_factors(self,n=None):
+        r"""
+        Counts the number of distinct factors of self.
+
+        INPUT:
+
+        -  ``n`` - an integer, or None.
+
+        OUTPUT:
+
+            If n is an integer, returns the number of distinct factors
+            of length n. If n is None, returns the total number of
+            distinct factors.
+
+        EXAMPLES::
+
+            sage: w = Word([1,2,1,2,3])
+            sage: w.number_of_factors()
+            13
+            sage: map(w.number_of_factors, range(6))
+            [1, 3, 3, 3, 2, 1]
+            
+        ::
+
+            sage: Word('1213121').number_of_factors()
+            22
+            sage: Word('1213121').number_of_factors(1)
+            3
+            
+        ::
+
+            sage: Word('a'*100).number_of_factors()
+            101
+            sage: Word('a'*100).number_of_factors(77)
+            1
+            
+        ::
+
+            sage: Word().number_of_factors()
+            1
+            sage: Word().number_of_factors(17)
+            0
+            
+        ::
+
+            sage: blueberry = Word("blueberry")
+            sage: blueberry.number_of_factors()
+            43
+            sage: map(blueberry.number_of_factors, range(10))
+            [1, 6, 8, 7, 6, 5, 4, 3, 2, 1]
+        """
+        return self.suffix_tree().number_of_factors(n)
+
+    def factor_iterator(self,n=None):
+        r"""
+        Generates distinct factors of ``self``.
+
+        INPUT:
+
+        -  ``n`` - an integer, or ``None``.
+
+        OUTPUT:
+
+            If ``n`` is an integer, returns an iterator over all distinct
+            factors of length ``n``. If ``n`` is ``None``, returns an iterator
+            generating all distinct factors.
+
+        EXAMPLES::
+
+            sage: w = Word('1213121')
+            sage: sorted( w.factor_iterator(0) )
+            [word: ]
+            sage: sorted( w.factor_iterator(10) )
+            []
+            sage: sorted( w.factor_iterator(1) )
+            [word: 1, word: 2, word: 3]
+            sage: sorted( w.factor_iterator(4) )
+            [word: 1213, word: 1312, word: 2131, word: 3121]
+            sage: sorted( w.factor_iterator() )
+            [word: , word: 1, word: 12, word: 121, word: 1213, word: 12131, word: 121312, word: 1213121, word: 13, word: 131, word: 1312, word: 13121, word: 2, word: 21, word: 213, word: 2131, word: 21312, word: 213121, word: 3, word: 31, word: 312, word: 3121]
+            
+        ::
+
+            sage: u = Word([1,2,1,2,3])
+            sage: sorted( u.factor_iterator(0) )
+            [word: ]
+            sage: sorted( u.factor_iterator(10) )
+            []
+            sage: sorted( u.factor_iterator(1) )
+            [word: 1, word: 2, word: 3]
+            sage: sorted( u.factor_iterator(5) )
+            [word: 12123]
+            sage: sorted( u.factor_iterator() )
+            [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]
+            
+        ::
+
+            sage: xxx = Word("xxx")
+            sage: sorted( xxx.factor_iterator(0) )
+            [word: ]
+            sage: sorted( xxx.factor_iterator(4) )
+            []
+            sage: sorted( xxx.factor_iterator(2) )
+            [word: xx]
+            sage: sorted( xxx.factor_iterator() )
+            [word: , word: x, word: xx, word: xxx]
+            
+        ::
+
+            sage: e = Word()
+            sage: sorted( e.factor_iterator(0) )
+            [word: ]
+            sage: sorted( e.factor_iterator(17) )
+            []
+            sage: sorted( e.factor_iterator() )
+            [word: ]
+
+        TESTS::
+
+            sage: type( Word('cacao').factor_iterator() )
+            <type 'generator'>
+        """
+        return self.suffix_tree().factor_iterator(n)
+
+    def factor_set(self):
+        r"""
+        Returns the set of factors of self.
+
+        EXAMPLES::
+
+            sage: Word('1213121').factor_set()   # random
+            Set of elements of <generator object at 0xa8fde6c>
+            sage: sorted(  Word([1,2,1,2,3]).factor_set()  )
+            [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]
+            sage: sorted(  Word("xx").factor_set()  )
+            [word: , word: x, word: xx]
+            sage: set( Word().factor_set() )
+            set([word: ])
+        """
+        return Set(set(self.factor_iterator()))
+
+    def commutes_with(self, other):
+        r"""
+        Returns True if self commutes with other, and False otherwise.
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('12').commutes_with(W('12'))
+            True
+            sage: W('12').commutes_with(W('11'))
+            False
+            sage: W().commutes_with(W('21'))
+            True
+        """
+        return (self * other) == (other * self)
+        
+    def conjugate(self, pos):
+        r"""
+        Returns the conjugate at pos of self.
+        
+        pos can be any integer, the distance used is the modulo by the length 
+        of self.
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('12112').conjugate(1)
+            word: 21121
+            sage: W().conjugate(2)
+            word: 
+            sage: W('12112').conjugate(8)
+            word: 12121
+            sage: W('12112').conjugate(-1)
+            word: 21211
+        """
+        if self.is_empty():
+            return self
+        pos_mod = pos % self.length()
+        return self[pos_mod:] * self[:pos_mod]
+        
+    def _conjugates_list(self):
+        r"""
+        Returns the list of conjugates of self, ordered from the 0-th to the 
+        (L-1)-st conjugate, where L is the length of self.
+        
+        TESTS::
+
+            sage: W = Word
+            sage: W('cbbca')._conjugates_list()
+            [word: cbbca, word: bbcac, word: bcacb, word: cacbb, word: acbbc]
+            sage: W('abcabc')._conjugates_list()
+            [word: abcabc,
+             word: bcabca,
+             word: cabcab,
+             word: abcabc,
+             word: bcabca,
+             word: cabcab]
+            sage: W()._conjugates_list()
+            [word: ]
+            sage: W('a')._conjugates_list()
+            [word: a]
+        """
+        S = [self]
+        for i in range(1,self.length()):
+            S.append(self.conjugate(i))
+        return S
+
+    def conjugates(self):
+        r"""
+        Returns the set of conjugates of self.
+        
+        TESTS::
+
+            sage: W = Word
+            sage: W('cbbca').conjugates() == set([W('cacbb'),W('bbcac'),W('acbbc'),W('cbbca'),W('bcacb')])
+            True
+            sage: W('abcabc').conjugates() == set([W('abcabc'),W('bcabca'),W('cabcab')])
+            True
+            sage: W().conjugates() == set([W()])
+            True
+            sage: W('a').conjugates() == set([W('a')])
+            True
+        """
+        S = set([self])
+        for i in range(1,self.primitive_length()):
+            S.add(self.conjugate(i))
+        return S
+
+    def conjugate_position(self, other):
+        r"""
+        Returns the position where self is conjugate with other.
+        Returns None if there is no such position.
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('12113').conjugate_position(W('31211'))
+            1
+            sage: W('12131').conjugate_position(W('12113')) is None
+            True
+            sage: W().conjugate_position(W('123')) is None
+            True
+        """
+        if self.length() != other.length():
+            return None
+        if self == other:
+            return 0
+        for l in xrange(1, other.length() - 1):
+            other = other.conjugate(1)
+            if self == other:
+                return l
+        return None
+
+    def is_conjugate_with(self, other):
+        r"""
+        Returns True if self is a conjugate of other, and False otherwise.
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('11213').is_conjugate_with(W('31121'))
+            True
+            sage: W().is_conjugate_with(W('123'))
+            False
+            sage: W('112131').is_conjugate_with(W('11213'))
+            False
+            sage: W('12131').is_conjugate_with(W('11213'))
+            True
+        """
+        return self.conjugate_position(other) is not None
+
+    def is_cadence(self, seq):
+        r"""
+        Returns True if seq is a cadence of self, and False otherwise.
+        
+        A *cadence* is an increasing sequence of indexes that all map to
+        the same letter.
+            
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('121132123').is_cadence([0, 2, 6])
+            True
+            sage: W('121132123').is_cadence([0, 1, 2])
+            False
+            sage: W('121132123').is_cadence([])
+            True
+        """
+        if len(seq) == 0:
+            return True
+        try:
+            it = iter(self)
+            s = islice(it, seq[0], None).next()
+            for i in xrange(1, len(seq)):
+                steps = seq[i] - seq[i-1]
+                for n in xrange(steps-1): it.next()
+                if it.next() != s:
+                    return False
+        except StopIteration:
+            return False
+        return True
+
+    def longest_common_prefix(self, other):
+        r"""
+        Returns the longest common prefix of self and other.
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: w = W('12345')
+            sage: y = W('1236777')
+            sage: w.longest_common_prefix(y)
+            word: 123
+            sage: w.longest_common_prefix(w)
+            word: 12345
+            sage: y.longest_common_prefix(w)
+            word: 123
+            sage: y.longest_common_prefix(w)==w.longest_common_prefix(y)
+            True
+            sage: y.longest_common_prefix(y)==y
+            True
+            sage: W().longest_common_prefix(w)
+            word: 
+            sage: w.longest_common_prefix(W()) == w
+            False
+            sage: w.longest_common_prefix(W()) == W()
+            True
+            sage: w.longest_common_prefix(w[:3]) == w[:3]
+            True
+            sage: w.longest_common_prefix(w[:3]) == w
+            False
+            sage: Word("11").longest_common_prefix(Word("1"))
+            word: 1
+
+        With infinite words::
+
+            sage: t = words.ThueMorseWord('ab')
+            sage: u = t[:10]
+            sage: u.longest_common_prefix(t)
+            word: abbabaabba
+            sage: u.longest_common_prefix(u)
+            word: abbabaabba
+        """
+        i=0
+        for i,(b,c) in enumerate(izip(self, other)):
+            if b != c:
+                return self[:i]
+        else:
+            return self[:i+1]
+
+    def longest_common_suffix(self, other):
+        r"""
+        Returns the longest common suffix of self and other.
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: w = W('112345678')
+            sage: u = W('1115678')
+            sage: w.longest_common_suffix(u)
+            word: 5678
+            sage: u.longest_common_suffix(u)
+            word: 1115678
+            sage: u.longest_common_suffix(w)
+            word: 5678
+            sage: w.longest_common_suffix(w)
+            word: 112345678
+            sage: y = W('549332345')
+            sage: w.longest_common_suffix(y)
+            word: 
+
+        TESTS:
+
+        With the empty word::
+
+            sage: w.longest_common_suffix(W())
+            word: 
+            sage: W().longest_common_suffix(w)
+            word: 
+            sage: W().longest_common_suffix(W())
+            word: 
+
+        With an infinite word::
+
+            sage: t=words.ThueMorseWord('ab')
+            sage: w.longest_common_suffix(t)
+            Traceback (most recent call last):
+            ...
+            TypeError: other must be a finite word
+        """
+        if not isinstance(other, FiniteWord_class):
+            raise TypeError, "other must be a finite word"
+        
+        if self.is_empty():
+            return self
+        if other.is_empty():
+            return other
+
+        iter = enumerate(izip(reversed(self), reversed(other)))
+        i,(b,c) = iter.next()
+        if b != c:
+            #In this case, return the empty word
+            return self[:0]
+
+        for i,(b,c) in iter:
+            if b != c:
+                return self[-i:]
+        else:
+            return self[-i-1:]
+
     def is_palindrome(self, f=None):
         r"""
-        Returns True if self is a palindrome (or a `f` -palindrome),
-        and False otherwise.
-        
-        - In French: Soit `f : \Sigma \rightarrow \Sigma` une
-          involution qui s'étend évidemment à un morphisme sur
-          `\Sigma^*`. On dit que `w\in\Sigma^*` est un
-          *`f`-pseudo-palindrome* [1], ou plus simplement un
-          *`f`-palindrome*, si `w=f(\tilde{w})` (extrait
-          de [2]).
-        
-        - In English Let `f : \Sigma \rightarrow \Sigma` be an
-          involution that extends to a morphism on
-          `\Sigma^*`. We say that `w\in\Sigma^*` is a
-          *`f`-palindrome* if `w=f(\tilde{w})` [2].
-        
-        Also called *`f` -pseudo-palindrome* [1].
-        
-        INPUT:
-        
-        
-        -  ``f`` - involution (default: None) on the alphabet
-           of self. It must be something that WordMorphism's constructor
-           understands (dict, str, ...).
-        
-        
-        OUTPUT:
-        
-        
-        -  ``boolean`` - if f is None, whether self is a
-           palindrome; otherwise, whether self is a f-palindrome.
-        
-        
-        EXAMPLES: Some palindromes...
-        
-        ::
-        
-            sage: W=Words('abcdefghijklmnopqrstuvwxyz I')
+        Returns True if self is a palindrome (or a `f`-palindrome), and
+        False otherwise.
+        
+        Let `f : \Sigma \rightarrow \Sigma` be an involution that extends 
+        to a morphism on `\Sigma^*`. We say that `w\in\Sigma^*` is a
+        *`f`-palindrome* if `w=f(\tilde{w})` [1]. Also called 
+        *`f`-pseudo-palindrome* [2].
+        
+        INPUT:
+
+        -  ``f`` - involution (default: None) on the alphabet of self. It must 
+           be callable on letters as well as words (e.g. WordMorphism).
+            
+        EXAMPLES::
+
+            sage: W = Word
             sage: W('esope reste ici et se repose').is_palindrome()
             False
             sage: W('esoperesteicietserepose').is_palindrome()
@@ -1083,49 +2298,54 @@
             True
             sage: Word('abcbdba').is_palindrome()
             False
-        
-        Some `f`-palindromes... You can use a str::
-        
-            sage: Word('aababb').is_palindrome('a->b,b->a')
-            True
-            sage: Word('abacbacbab').is_palindrome('a->b,b->a,c->c')
-            True
-        
-        You can use WordMorphism::
-        
+
+        Some `f`-palindromes::
+
             sage: f = WordMorphism('a->b,b->a')
             sage: Word('aababb').is_palindrome(f)
             True
-        
-        You can use a dictionary::
-        
-            sage: f = {'a':'b','b':'a'}
+
+        ::
+        
+            sage: f = WordMorphism('a->b,b->a,c->c')
+            sage: Word('abacbacbab').is_palindrome(f)
+            True
+
+        ::
+            
+            sage: f = WordMorphism({'a':'b','b':'a'})
             sage: Word('aababb').is_palindrome(f)
             True
+
+        ::
+
+            sage: f = WordMorphism({0:[1],1:[0]})
             sage: w = words.ThueMorseWord()[:8]; w
             word: 01101001
-            sage: w.is_palindrome(f={0:[1],1:[0]})
-            True
-        
-        self must be in the domain of the involution::
-        
+            sage: w.is_palindrome(f)
+            True
+
+        The word must be in the domain of the involution::
+
             sage: f = WordMorphism('a->a')
             sage: Word('aababb').is_palindrome(f)
             Traceback (most recent call last):
             ...
-            ValueError: self must be in the domain of the given involution
-        
-        The given involution must be an involution::
-        
+            ValueError: b not in alphabet!
+            
+        TESTS:
+
+        If the given involution is not an involution::
+
             sage: f = WordMorphism('a->b,b->b')
             sage: Word('abab').is_palindrome(f)
             Traceback (most recent call last):
             ...
             ValueError: f must be an involution
-        
-        TESTS::
-        
-            sage: Y = Words('ab')
+            
+        ::
+
+            sage: Y = Word
             sage: Y().is_palindrome()
             True
             sage: Y('a').is_palindrome()
@@ -1136,7 +2356,7 @@
             True
             sage: Y('aa').is_palindrome() 
             True
-            sage: E = 'a->b,b->a'
+            sage: E = WordMorphism('a->b,b->a')
             sage: Y().is_palindrome(E)
             True
             sage: Y('a').is_palindrome(E)
@@ -1152,54 +2372,84 @@
         
         REFERENCES:
 
-        - [1] V. Anne, L.Q. Zamboni, I. Zorca, Palindromes and
-          Pseudo- Palindromes in Episturmian and Pseudo-Palindromic Infinite
-          Words, in : S. Brlek, C. Reutenauer (Eds.), Words 2005,
-          Publications du LaCIM, Vol. 36 (2005) 91-100.
-
-        - [2] S. Labbé, Propriétés combinatoires des `f`-palindromes, Mémoire de
-          maîtrise en Mathématiques, Montréal, UQAM, 2008, 109 pages.
-        """
+        -   [1] S. Labbé, Propriétés combinatoires des `f`-palindromes,  
+            Mémoire de maîtrise en Mathématiques, Montréal, UQAM, 2008, 
+            109 pages.
+        -   [2] V. Anne, L.Q. Zamboni, I. Zorca, Palindromes and Pseudo-
+            Palindromes in Episturmian and Pseudo-Palindromic Infinite Words,
+            in : S. Brlek, C. Reutenauer (Eds.), Words 2005, Publications du
+            LaCIM, Vol. 36 (2005) 91--100.
+        """
+        l = self.length()
         if f is None:
-            l = len(self)
             return self[:l/2] == self[l/2 + l%2:].reversal()
-            
-        from sage.combinat.words.morphism import WordMorphism
-        f = WordMorphism(f)
-        
-        if self not in f.domain():
-            raise ValueError, "self must be in the domain of "\
-                                 +"the given involution"
-        
-        if not f.is_involution():
-            raise ValueError, "f must be an involution"
-            
-        l = len(self)
-        return self[:l/2 + l%2] == f(self[l/2:].reversal()) 
-            
-    def lps(self, f=None):
-        r"""
-        Returns the longest palindromic (or `f`-palindromic) suffix
-        of self.
-        
-        INPUT:
-        
-        
-        -  ``f`` - involution (default: None) on the alphabet
-           of self. It must be something that WordMorphism's constructor
-           understands (dict, str, ...).
-        
-        
-        OUTPUT:
-        
-        
-        -  ``word`` - If f is None, the longest palindromic
-           suffix of self; otherwise, the longest f-palindromic suffix of
-           self.
-        
-        
-        EXAMPLES::
-        
+        else:    
+            from sage.combinat.words.morphism import WordMorphism
+            if not isinstance(f, WordMorphism):
+                f = WordMorphism(f)
+            if not f.is_involution():
+                raise ValueError, "f must be an involution"
+            return self[:l/2 + l%2] == f(self[l/2:].reversal()) 
+            
+    ###########################################################################
+    ##### DEPRECATION WARNINGS ################################################
+    ##### Added July 2009 #####################################################
+    ###########################################################################
+    def _lps(self, l=None, f=None):
+        r"""
+        Returns the longest palindromic (or `f`-palindromic) suffix of self.
+        
+        INPUT:
+
+        -  ``f`` - involution (default: None) on the alphabet of self. It must 
+           be callable on letters as well as words (e.g. WordMorphism).
+        -  ``l`` - integer (default: None) the length of the longest palindrome 
+           suffix of self[:-1], if known.
+            
+        OUTPUT:
+
+            word -- If f is None, the longest palindromic suffix of self;
+                    otherwise, the longest f-palindromic suffix of self.
+
+        EXAMPLES::
+
+            sage: Word('0111')._lps()
+            doctest:1: DeprecationWarning: _lps is deprecated, use lps instead!
+            word: 111
+            sage: Word('011101')._lps()
+            word: 101
+            sage: Word('6667')._lps()
+            word: 7
+            sage: Word('abbabaab')._lps()
+            word: baab
+            sage: Word()._lps()
+            word: 
+            sage: f = WordMorphism('a->b,b->a')
+            sage: Word('abbabaab')._lps(f=f)
+            word: abbabaab
+        """
+        from sage.misc.misc import deprecation
+        deprecation("_lps is deprecated, use lps instead!")
+        return self.lps(l=l, f=f)
+
+    def lps(self, f=None, l=None):
+        r"""
+        Returns the longest palindromic (or `f`-palindromic) suffix of self.
+                
+        INPUT:
+
+        -  ``f`` - involution (default: None) on the alphabet of self. It must 
+           be callable on letters as well as words (e.g. WordMorphism).
+        -  ``l`` - integer (default: None) the length of the longest palindrome 
+           suffix of self[:-1], if known.
+            
+        OUTPUT:
+
+            word -- If f is None, the longest palindromic suffix of self;
+                    otherwise, the longest f-palindromic suffix of self.
+                
+        EXAMPLES::
+
             sage: Word('0111').lps()
             word: 111
             sage: Word('011101').lps()
@@ -1210,60 +2460,29 @@
             word: baab
             sage: Word().lps()
             word: 
-            sage: Word('abbabaab').lps('a->b,b->a')
+            sage: f = WordMorphism('a->b,b->a')
+            sage: Word('abbabaab').lps(f=f)
             word: abbabaab
-        """
-        for i in range(len(self)+1):
-            fact = self[i:]
-            if fact.is_palindrome(f=f):
-                return fact
-        
-    def _lps(self, l=None, f=None):
-        r"""
-        Returns the longest palindromic (or `f`-palindromic) suffix
-        of self.
-        
-        INPUT:
-        
-        
-        -  ``f`` - involution (default: None) on the alphabet
-           of self. It must be something that WordMorphism's constructor
-           understands (dict, str, ...).
-        
-        -  ``l`` - integer (default: None) the length of the
-           longest palindrome suffix of self[:-1]
-        
-        
-        OUTPUT:
-        
-        
-        -  ``word`` - If f is None, the longest palindromic
-           suffix of self; otherwise, the longest f-palindromic suffix of
-           self.
-        
-        
-        EXAMPLES::
-        
-            sage: W = Words('1234')
+            sage: W = Word
             sage: w = W('33412321')
-            sage: w._lps(3)
+            sage: w.lps(l=3)
             word: 12321
-            sage: Y = Words('01')
+            sage: Y = Word
             sage: w = Y('01101001')
-            sage: w._lps(l=2)
+            sage: w.lps(l=2)
             word: 1001
-            sage: w._lps()          
+            sage: w.lps()          
             word: 1001
-            sage: w._lps(None)
+            sage: w.lps(l=None)
             word: 1001
-            sage: Y()._lps(2)
-            Traceback (most recent call last):
-            ...
-            IndexError: word index out of range
-            sage: v=Words('ab')('abbabaab')
-            sage: pal=v[:0] 
-            sage: for i in range(1,len(v)+1): 
-            ...     pal=v[:i]._lps(len(pal))
+            sage: Y().lps(l=2)
+            Traceback (most recent call last):
+            ...
+            IndexError: list index out of range
+            sage: v = Word('abbabaab')
+            sage: pal = v[:0] 
+            sage: for i in range(1, v.length()+1): 
+            ...     pal = v[:i].lps(l=pal.length())
             ...     print pal
             ...   
             word: a
@@ -1274,10 +2493,11 @@
             word: aba
             word: aa
             word: baab
-            sage: v=Words('ab')('abbabaab')
-            sage: pal=v[:0] 
-            sage: for i in range(1,len(v)+1): 
-            ...     pal=v[:i]._lps(len(pal),'a->b,b->a')
+            sage: f = WordMorphism('a->b,b->a')
+            sage: v = Word('abbabaab')
+            sage: pal = v[:0] 
+            sage: for i in range(1, v.length()+1): 
+            ...     pal = v[:i].lps(f=f, l=pal.length())
             ...     print pal
             ...   
             word: 
@@ -1289,11 +2509,15 @@
             word: bbabaa
             word: abbabaab
         """
+        #If the length of the lps of self[:-1] is not known:
         if l == None:
-            return self.lps(f=f)
-                    
-        #If l == len(w[:-1]), there is no shortcut
-        if len(self) == l + 1:
+            for i in range(self.length()+1):
+                fact = self[i:]
+                if fact.is_palindrome(f=f):
+                    return fact
+                    
+        #If l == w[:-1].length(), there is no shortcut
+        if self.length() == l + 1:
             return self.lps(f=f)
         
         #Obtain the letter to the left (g) and to the right (d) of the 
@@ -1301,54 +2525,57 @@
         g = self[-l-2]
         d = self[-1]
         
-        #If the word g*d is a $f$-palindrome, the result follows
-        if self.parent()([g, d]).is_palindrome(f=f):
-            return self[-l-2:]
-        
-        #Otherwise, the length of the lps of self is smallest than l+2
-        else:
-            return self[-l-1:].lps(f=f)
-                
+        #If the word g*d is a `f`-palindrome, the result follows
+        if f is None:
+            if g == d:
+                return self[-l-2:]
+            else:
+                #Otherwise, the length of the lps of self is smallest than l+2
+                return self[-l-1:].lps()
+        else:
+            from sage.combinat.words.morphism import WordMorphism
+            f = WordMorphism(f)
+            if f(g)[0] == d:
+                return self[-l-2:]
+            else:
+                return self[-l-1:].lps(f=f)
+
     def palindromic_lacunas_study(self, f=None):
         r"""
-        Returns interesting statistics about longest
-        (`f`-)palindromic suffixes and lacunas of self (see [1] and
-        [2]).
-        
-        Note that a word `w` has at most `|w| + 1`
-        different palindromic factors (see [4]).
-        
-        INPUT:
-        
-        
-        -  ``f`` - involution (default: None) on the alphabet
-           of self. It must be something that WordMorphism's constructor
-           understand (dict, str, ...).
-        
-        
-        OUTPUT:
-        
-        
-        -  ``list`` - list of the length of the longest
-           palindromic suffix (lps) for each non-empty prefix of self;
-        
-        -  ``list`` - list of all the lacunas, i.e. positions
-           where there is no unioccurrent lps;
-        
+        Returns interesting statistics about longest (`f`-)palindromic suffixes
+        and lacunas of self (see [1] and [2]).
+                    
+        Note that a word `w` has at most `|w| + 1` different palindromic factors
+        (see [3]).
+
+        INPUT:
+
+        -  ``f`` - involution (default: None) on the alphabet of self. It must 
+           be callable on letters as well as words (e.g. WordMorphism).
+                             
+        OUTPUT:
+
+        -  ``list`` - list of the length of the longest palindromic
+           suffix (lps) for each non-empty prefix of self;
+        -  ``list`` - list of all the lacunas, i.e. positions where there is no
+           unioccurrent lps;
         -  ``set`` - set of palindromic factors of self.
-        
-        
-        EXAMPLES::
-        
-            sage: W=Words('ab')
-            sage: a,b,c = W('abbabaabbaab').palindromic_lacunas_study()                                         
+            
+        EXAMPLES::
+
+            sage: W = Word
+            sage: a,b,c = W('abbabaabbaab').palindromic_lacunas_study()
             sage: a
             [1, 1, 2, 4, 3, 3, 2, 4, 2, 4, 6, 8]
             sage: b
             [8, 9]
             sage: c          # random order
             set([word: , word: b, word: bab, word: abba, word: bb, word: aa, word: baabbaab, word: baab, word: aba, word: aabbaa, word: a])
-            sage: a,b,c = W('abbabaab').palindromic_lacunas_study(f='a->b,b->a')                                         
+
+        ::
+
+            sage: f = WordMorphism('a->b,b->a')
+            sage: a,b,c = W('abbabaab').palindromic_lacunas_study(f=f)
             sage: a
             [0, 2, 0, 2, 2, 4, 6, 8]
             sage: b
@@ -1357,43 +2584,36 @@
             set([word: , word: ba, word: baba, word: ab, word: bbabaa, word: abbabaab])
             sage: c == set([W(), W('ba'), W('baba'), W('ab'), W('bbabaa'), W('abbabaab')])
             True
-        
-        REFERENCES:
-
-        - [1] A. Blondin-Massé, S. Brlek, S. Labbé, Palindromic
-          lacunas of the Thue-Morse word, Proc. GASCOM 2008 (June
-          16-20 2008, Bibbiena, Arezzo-Italia), 53-67.
-
-        - [2] A. Blondin-Massé, S. Brlek, A.  Frosini, S. Labbé,
-          S. Rinaldi, Reconstructing words from a fixed palindromic
-          length sequence, Proc. TCS 2008, 5th IFIP International
-          Conference on Theoretical Computer Science (September 8-10
-          2008, Milano, Italia), accepted.
-
-        - [3] S. Labbé, Propriétés combinatoires des
-          `f`-palindromes, Mémoire de maitrise en Mathématiques,
-          Montréal, UQAM, 2008, 109 pages.
-
-        - [4] X. Droubay, J. Justin, G.  Pirillo, Episturmian words
-          and some constructions of de Luca and Rauzy,
-          Theoret. Comput. Sci. 255 (2001) 539-553.
+            
+        REFERENCES:
+
+        -   [1] A. Blondin-Massé, S. Brlek, S. Labbé, Palindromic lacunas
+            of the Thue-Morse word, Proc. GASCOM 2008 (June 16-20 2008,
+            Bibbiena, Arezzo-Italia), 53--67.
+        -   [2] A. Blondin-Massé, S. Brlek, A. Frosini, S. Labbé, S. Rinaldi,
+            Reconstructing words from a fixed palindromic length sequence, 
+            Proc. TCS 2008, 5th IFIP International Conference on Theoretical
+            Computer Science (September 8-10 2008, Milano, Italia), accepted.
+        -   [3] X. Droubay, J. Justin, G. Pirillo, Episturmian words and
+            some constructions of de Luca and Rauzy, Theoret. Comput. Sci.
+            255 (2001) 539--553.
         """
         #Initialize the results of computations
         palindromes = set()
-        lengths_lps = [None] * len(self)
+        lengths_lps = [None] * self.length()
         lacunas = []
         
         #Initialize the first lps
-        pal = self.parent()()
+        pal = self[:0]
         palindromes.add(pal)
         
         #For all the non-empty prefixes of self,
-        for i in xrange(len(self)):
-            
-            #Compute its longest $f$-palindromic suffix using the preceding lps (pal)
-            pal = self[:i+1]._lps(l=len(pal),f=f)
-
-            lengths_lps[i] = len(pal)
+        for i in xrange(self.length()):
+            
+            #Compute its longest `f`-palindromic suffix using the preceding lps (pal)
+            pal = self[:i+1].lps(l=pal.length(),f=f)
+
+            lengths_lps[i] = pal.length()
 
             if pal in palindromes: 
                 lacunas.append(i)
@@ -1404,28 +2624,23 @@
 
     def lengths_lps(self, f=None):
         r"""
-        Returns the list of the length of the longest palindromic suffix
-        (lps) for each non-empty prefix of self.
-        
-        It corresponds to the function `G_w` defined in [2].
-        
-        INPUT:
-        
-        
-        -  ``f`` - involution (default: None) on the alphabet
-           of self. It must be something that WordMorphism's constructor
-           understand (dict, str, ...).
-        
-        
-        OUTPUT:
-        
-        
-        -  ``list`` - list of the length of the longest
-           palindromic suffix (lps) for each non-empty prefix of self.
-        
-        
-        EXAMPLES::
-        
+        Returns the list of the length of the longest palindromic
+        suffix (lps) for each non-empty prefix of self.
+        
+        It corresponds to the function `G_w` defined in [1].
+
+        INPUT:
+
+        -  ``f`` - involution (default: None) on the alphabet of self. It must 
+           be callable on letters as well as words (e.g. WordMorphism).
+                             
+        OUTPUT:
+
+            list -- list of the length of the longest palindromic
+                    suffix (lps) for each non-empty prefix of self.
+                    
+        EXAMPLES::
+
             sage: Word().lengths_lps()             
             []
             sage: Word('a').lengths_lps()
@@ -1434,22 +2649,26 @@
             [1, 2, 3]
             sage: Word('abbabaabbaab').lengths_lps()         
             [1, 1, 2, 4, 3, 3, 2, 4, 2, 4, 6, 8]
-            sage: Word('abbabaabbaab').lengths_lps(f='a->b,b->a')
+
+        ::
+
+            sage: f = WordMorphism('a->b,b->a')
+            sage: Word('abbabaabbaab').lengths_lps(f)
             [0, 2, 0, 2, 2, 4, 6, 8, 4, 6, 4, 6]
-            sage: Word([5,8,5,5,8,8,5,5,8,8,5,8,5]).lengths_lps(f={5:[8],8:[5]})
+
+        ::
+
+            sage: f = WordMorphism({5:[8],8:[5]})
+            sage: Word([5,8,5,5,8,8,5,5,8,8,5,8,5]).lengths_lps(f)
             [0, 2, 2, 0, 2, 4, 6, 4, 6, 8, 10, 12, 4]
         
         REFERENCES:
 
-        - [1] A. Blondin-Massé, S. Brlek, S. Labbé, Palindromic
-          lacunas of the Thue-Morse word, Proc. GASCOM 2008 (June
-          16-20 2008, Bibbiena, Arezzo-Italia), 53-67.
-
-        - [2] A. Blondin-Massé, S. Brlek, A.  Frosini, S. Labbé,
-          S. Rinaldi, Reconstructing words from a fixed palindromic
-          length sequence, Proc. TCS 2008, 5th IFIP International
-          Conference on Theoretical Computer Science (September 8-10
-          2008, Milano, Italia), accepted.
+        -   [1] A. Blondin-Massé, S. Brlek, A. Frosini, S. Labbé, 
+            S. Rinaldi, Reconstructing words from a fixed palindromic length 
+            sequence, Proc. TCS 2008, 5th IFIP International Conference on 
+            Theoretical Computer Science (September 8-10 2008, Milano, 
+            Italia), accepted.
         """
         return self.palindromic_lacunas_study(f=f)[0]
 
@@ -1459,82 +2678,78 @@
         
         A *lacuna* is a position in a word where the longest palindromic
         suffix is not unioccurrent (see [1]).
-        
-        INPUT:
-        
-        
-        -  ``f`` - involution (default: None) on the alphabet
-           of self. It must be something that WordMorphism's constructor
-           understands (dict, str, ...).
-        
-        
-        OUTPUT:
-        
-        
-        -  ``list`` - list of all the lacunas of self.
-        
-        
-        EXAMPLES::
-        
+
+        INPUT:
+
+        -  ``f`` - involution (default: None) on the alphabet of self. It must 
+           be callable on letters as well as words (e.g. WordMorphism).
+                             
+        OUTPUT:
+
+            list -- list of all the lacunas of self.
+            
+        EXAMPLES::
+
+            sage: w = Word([0,1,1,2,3,4,5,1,13,3])
+            sage: w.lacunas()
+            [7, 9]
             sage: words.ThueMorseWord()[:100].lacunas()
             [8, 9, 24, 25, 32, 33, 34, 35, 36, 37, 38, 39, 96, 97, 98, 99]
-            sage: words.ThueMorseWord()[:50].lacunas(f={0:[1],1:[0]}) 
+            sage: f = WordMorphism({0:[1],1:[0]})
+            sage: words.ThueMorseWord()[:50].lacunas(f) 
             [0, 2, 4, 12, 16, 17, 18, 19, 48, 49]
-        
-        REFERENCES:
-
-        - [1] A. Blondin-Massé, S. Brlek, S. Labbé, Palindromic
-          lacunas of the Thue-Morse word, Proc. GASCOM 2008 (June
-          16-20 2008, Bibbiena, Arezzo-Italia), 53-67.
+            
+        REFERENCES:
+
+        -   [1] A. Blondin-Massé, S. Brlek, S. Labbé, Palindromic lacunas
+            of the Thue-Morse word, Proc. GASCOM 2008 (June 16-20 2008,
+            Bibbiena, Arezzo-Italia), 53--67.
         """
         return self.palindromic_lacunas_study(f=f)[1]
 
     def lengths_unioccurrent_lps(self, f=None):
         r"""
-        Returns the list of the lengths of the unioccurrent longest
-        palindromic suffixes (lps) for each non-empty prefix of self. No
-        unioccurrent lps are indicated by None.
-        
-        It corresponds to the function `H_w` defined in [1] and
-        [2].
-        
-        INPUT:
-        
-        
-        -  ``f`` - involution (default: None) on the alphabet
-           of self. It must be something that WordMorphism's constructor
-           understand (dict, str, ...).
-        
-        
-        OUTPUT:
-        
-        
-        -  ``list`` - list of the length of the unioccurrent
-           longest palindromic suffix (lps) for each non-empty prefix of
-           self. No unioccurrent lps are indicated by None.
-        
-        
-        EXAMPLES::
-        
+        Returns the list of the lengths of the unioccurrent longest palindromic
+        suffixes (lps) for each non-empty prefix of self. No unioccurrent lps
+        are indicated by None.
+        
+        It corresponds to the function `H_w` defined in [1] and [2].
+
+        INPUT:
+
+        -  ``f`` - involution (default: None) on the alphabet of self. It must 
+           be callable on letters as well as words (e.g. WordMorphism).
+                             
+        OUTPUT:
+
+            list -- list of the length of the unioccurrent longest palindromic
+                    suffix (lps) for each non-empty prefix of self.
+                    No unioccurrent lps are indicated by None.
+        
+        EXAMPLES::
+
+            sage: w = Word([0,1,1,2,3,4,5,1,13,3])
+            sage: w.lengths_unioccurrent_lps()
+            [1, 1, 2, 1, 1, 1, 1, None, 1, None]
             sage: f = words.FibonacciWord()[:20]
             sage: f.lengths_unioccurrent_lps() == f.lengths_lps() 
             True
-            sage: words.ThueMorseWord()[:20].lengths_unioccurrent_lps()
+            sage: t = words.ThueMorseWord()
+            sage: t[:20].lengths_unioccurrent_lps()
             [1, 1, 2, 4, 3, 3, 2, 4, None, None, 6, 8, 10, 12, 14, 16, 6, 8, 10, 12]
-            sage: words.ThueMorseWord()[:15].lengths_unioccurrent_lps(f={1:[0],0:[1]})
+            sage: f = WordMorphism({1:[0],0:[1]})
+            sage: t[:15].lengths_unioccurrent_lps(f)
             [None, 2, None, 2, None, 4, 6, 8, 4, 6, 4, 6, None, 4, 6]
         
         REFERENCES:
 
-        - [1] A. Blondin-Massé, S. Brlek, S. Labbé, Palindromic
-          lacunas of the Thue-Morse word, Proc. GASCOM 2008 (June
-          16-20 2008, Bibbiena, Arezzo-Italia), 53-67.
-
-        - [2] A. Blondin-Massé, S. Brlek, A.  Frosini, S. Labbé,
-          S. Rinaldi, Reconstructing words from a fixed palindromic
-          length sequence, Proc. TCS 2008, 5th IFIP International
-          Conference on Theoretical Computer Science (September 8-10
-          2008, Milano, Italia), accepted.
+        -   [1] A. Blondin-Massé, S. Brlek, S. Labbé, Palindromic lacunas of
+            the Thue-Morse word, Proc. GASCOM 2008 (June 16-20 2008, Bibbiena,
+            Arezzo-Italia), 53--67.
+        -   [2] A. Blondin-Massé, S. Brlek, A. Frosini, S. Labbé, S. Rinaldi,
+            Reconstructing words from a fixed palindromic length sequence,
+            Proc. TCS 2008, 5th IFIP International Conference on Theoretical
+            Computer Science (September 8-10 2008, Milano, Italia), accepted.
         """
         l = self.lengths_lps(f=f)
         for i in self.lacunas(f=f):
@@ -1543,28 +2758,21 @@
 
     def palindromes(self, f=None):
         r"""
-        Returns the set of all palindromic (or `f`-palindromic)
-        factors of self.
-        
-        INPUT:
-        
-        
-        -  ``f`` - involution (default: None) on the alphabet
-           of self. It must be something that WordMorphism's constructor
-           understands (dict, str, ...).
-        
-        
-        OUTPUT:
-        
-        
-        -  ``set`` - If f is None, the set of all palindromic
-           factors of self; otherwise, the set of all f-palindromic factors of
-           self.
-        
-        
-        EXAMPLES::
-        
-            sage: W = Words('01')
+        Returns the set of all palindromic (or `f`-palindromic) factors of self.
+
+        INPUT:
+
+        -  ``f`` - involution (default: None) on the alphabet of self. It must 
+           be callable on letters as well as words (e.g. WordMorphism).
+                             
+        OUTPUT:
+
+            set -- If f is None, the set of all palindromic factors of self;
+                   otherwise, the set of all f-palindromic factors of self.
+                
+        EXAMPLES::
+
+            sage: W = Word
             sage: sorted(W('01101001').palindromes())
             [word: , word: 0, word: 00, word: 010, word: 0110, word: 1, word: 1001, word: 101, word: 11]
             sage: sorted(W('00000').palindromes())   
@@ -1575,7 +2783,8 @@
             [word: ]
             sage: sorted(W().palindromes())  
             [word: ]
-            sage: sorted(Word('abbabaab').palindromes('a->b,b->a'))
+            sage: f = WordMorphism('a->b,b->a')
+            sage: sorted(Word('abbabaab').palindromes(f))
             [word: , word: ab, word: abbabaab, word: ba, word: baba, word: bbabaa]
         """
         return self.palindromic_lacunas_study(f=f)[2]
@@ -1585,32 +2794,26 @@
         Returns the defect of self.
         
         The *defect* of a finite word `w` is given by
-        `D(w)=|w|+1-|PAL(w)|`, where `PAL(w)` denotes the
-        set of palindromic factors of `w` (including the empty
-        word). See [1].
-        
-        INPUT:
-        
-        
-        -  ``f`` - involution (default: None) on the alphabet
-           of self. It must be something that WordMorphism's constructor
-           understands (dict, str, ...).
-        
-        
-        OUTPUT:
-        
-        
-        -  ``integer`` - If f is None, the palindromic defect
-           of self; otherwise, the f-palindromic defect of self.
-        
-        
-        EXAMPLES::
-        
+        `D(w)=|w|+1-|PAL(w)|`, where `PAL(w)` denotes the set of palindromic
+        factors of `w` (including the empty word). See [1].
+        
+        INPUT:
+
+        -  ``f`` - involution (default: None) on the alphabet of self. It must 
+           be callable on letters as well as words (e.g. WordMorphism).
+                             
+        OUTPUT:
+
+            integer -- If f is None, the palindromic defect of self;
+                       otherwise, the f-palindromic defect of self.
+                       
+        EXAMPLES::
+
             sage: words.ThueMorseWord()[:100].defect()
             16
             sage: words.FibonacciWord()[:100].defect()
             0
-            sage: W = Words('01')
+            sage: W = Word
             sage: W('000000000000').defect()
             0
             sage: W('011010011001').defect()
@@ -1621,102 +2824,98 @@
             0
             sage: Word('abbabaabbaababba').defect()
             2
-            sage: Word('abbabaabbaababba').defect('a->b,b->a')
-            4
-        
-        REFERENCES:
-
-        - [1] S. Brlek, S. Hamel, M. Nivat, C. Reutenauer, On the
-          Palindromic Complexity of Infinite Words, in J. Berstel, J.
-          Karhumaki, D. Perrin, Eds, Combinatorics on Words with
-          Applications, International Journal of Foundation of
-          Computer Science, Vol. 15, No. 2 (2004) 293-306.
-        """
-        return len(self)+1-len(self.palindromes(f=f))
+
+        ::
+
+            sage: f = WordMorphism('a->b,b->a')
+            sage: Word('abbabaabbaababba').defect(f)
+            4
+        
+        REFERENCES:
+
+        -   [1] S. Brlek, S. Hamel, M. Nivat, C. Reutenauer, On the Palindromic
+            Complexity of Infinite Words, in J. Berstel, J. Karhumaki, 
+            D. Perrin, Eds, Combinatorics on Words with Applications,
+            International Journal of Foundation of Computer Science, Vol. 15,
+            No. 2 (2004) 293--306.
+        """
+        return self.length()+1-len(self.palindromes(f=f))
 
     def is_full(self, f=None):
         r"""
         Returns True if self has defect 0, and False otherwise.
         
         A word is *full* if its defect is zero (see [1]).
-        
-        INPUT:
-        
-        
-        -  ``f`` - involution (default: None) on the alphabet
-           of self. It must be something that WordMorphism's constructor
-           understands (dict, str, ...).
-        
-        
-        OUTPUT:
-        
-        
-        -  ``boolean`` - If f is None, whether self is full;
-           otherwise, whether self is full of `f`-palindromes.
-        
-        
-        EXAMPLES::
-        
+
+        INPUT:
+
+        -  ``f`` - involution (default: None) on the alphabet of self. It must 
+           be callable on letters as well as words (e.g. WordMorphism).
+                             
+        OUTPUT:
+
+            boolean -- If f is None, whether self is full;
+                       otherwise, whether self is full of `f`-palindromes.
+                       
+        EXAMPLES::
+
             sage: words.ThueMorseWord()[:100].is_full()
             False
             sage: words.FibonacciWord()[:100].is_full()
             True
-            sage: Words('0')('000000000000000').is_full()
-            True
-            sage: Words('01')('011010011001').is_full()
-            False
-            sage: Words('123456789')('2194').is_full()
+            sage: Word('000000000000000').is_full()
+            True
+            sage: Word('011010011001').is_full()
+            False
+            sage: Word('2194').is_full()
             True
             sage: Word().is_full()
             True
-            sage: Word().is_full('a->b,b->a')
+
+        ::
+
+            sage: f = WordMorphism('a->b,b->a')
+            sage: Word().is_full(f)
             True
             sage: w = Word('ab')
             sage: w.is_full()
             True
-            sage: w.is_full('a->b,b->a')
-            False
-        
-        REFERENCES:
-
-        - [1] S. Brlek, S. Hamel, M. Nivat, C. Reutenauer, On the
-          Palindromic Complexity of Infinite Words, in J. Berstel, J.
-          Karhumaki, D. Perrin, Eds, Combinatorics on Words with
-          Applications, International Journal of Foundation of
-          Computer Science, Vol. 15, No. 2 (2004) 293-306.
+            sage: w.is_full(f)
+            False
+            
+        REFERENCES:
+
+        -   [1] S. Brlek, S. Hamel, M. Nivat, C. Reutenauer, On the Palindromic
+            Complexity of Infinite Words, in J. Berstel, J. Karhumaki, 
+            D. Perrin, Eds, Combinatorics on Words with Applications,
+            International Journal of Foundation of Computer Science, Vol. 15,
+            No. 2 (2004) 293--306.
         """
         return self.defect(f=f) == 0
 
     def palindromic_closure(self, side='right', f=None):
         r"""
-        Returns the shortest palindrome having self as a prefix (or as a
-        suffix if side=='left').
-        
-        Retourne le plus petit palindrome ayant self comme prefixe (ou
-        comme suffixe si side=='left').
-        
-        INPUT:
-        
-        
-        -  ``side`` - 'right' or 'left' (default: 'right') the
-           direction of the closure
-        
-        -  ``f`` - involution (default: None) on the alphabet
-           of self. It must be something that WordMorphism's constructor
-           understands (dict, str, ...).
-        
-        
-        OUTPUT:
-        
-        
-        -  ``word`` - If f is None, the right palindromic
-           closure of self; otherwise, the right f-palindromic closure of
-           self. If side is 'left', the left palindromic closure.
-        
-        
-        EXAMPLES::
-        
-            sage: W = Words('1234567890')
+        Returns the shortest palindrome having self as a prefix 
+        (or as a suffix if side=='left').
+        
+        See [1].
+
+        INPUT:
+
+        -  ``side`` - 'right' or 'left' (default: 'right') the direction of the 
+           closure
+        -  ``f`` - involution (default: None) on the alphabet of self. It must 
+           be callable on letters as well as words (e.g. WordMorphism).
+                             
+        OUTPUT:
+
+            word -- If f is None, the right palindromic closure of self;
+                    otherwise, the right f-palindromic closure of self.
+                    If side is 'left', the left palindromic closure.
+                    
+        EXAMPLES::
+
+            sage: W = Word
             sage: W('1233').palindromic_closure()
             word: 123321
             sage: W('12332').palindromic_closure()
@@ -1730,166 +2929,68 @@
             sage: w = Word('abbaba')                  
             sage: w.palindromic_closure()             
             word: abbababba
-            sage: w.palindromic_closure(f='a->b,b->a')
+
+        ::
+
+            sage: f = WordMorphism('a->b,b->a')
+            sage: w.palindromic_closure(f=f)
             word: abbabaab
-            sage: w.palindromic_closure(f='a->b,b->a',side='left')
+            sage: w.palindromic_closure(f=f, side='left')
             word: babaabbaba
-            sage: w.palindromic_closure(f='a->b,b->b',side='left')
-            Traceback (most recent call last):
-            ...
-            ValueError: f must be an involution
-            sage: w.palindromic_closure(f='a->c,c->a',side='left')
-            Traceback (most recent call last):
-            ...
-            ValueError: self must be in the domain of the given involution
-        
-        REFERENCES:
-
-        - [1] A. de Luca, A. De Luca, Pseudopalindrome closure
-          operators in free monoids, Theoret. Comput. Sci. 362 (2006)
-          282-300.
+
+        TESTS::
+
+            sage: f = WordMorphism('a->c,c->a')
+            sage: w.palindromic_closure(f=f, side='left')
+            Traceback (most recent call last):
+            ...
+            ValueError: b not in alphabet!
+            
+        REFERENCES:        
+
+        -   [1] A. de Luca, A. De Luca, Pseudopalindrome closure operators 
+            in free monoids, Theoret. Comput. Sci. 362 (2006) 282--300.
         """
         if f is None:
             if side == 'right':
-                l = len(self.lps())
-                return self * self[-(l+1)::-1]
+                l = self.lps().length()
+                #return self * self[-(l+1)::-1]
+                return self * self[:self.length()-l].reversal()
             elif side == 'left':
-                l = len(self.reversal().lps())
+                l = self.reversal().lps().length()
                 return self[:l-1:-1] * self
             else:
                 raise ValueError, "side must be either 'left' or 'right' (not %s) " % side
         else:
             from sage.combinat.words.morphism import WordMorphism
             f = WordMorphism(f)
-            
-            if self not in f.domain():
-                raise ValueError, "self must be in the domain of "\
-                                     +"the given involution"
-            
             if not f.is_involution():
                 raise ValueError, "f must be an involution"
-           
             if side == 'right':
-                l = len(self.lps(f=f))
+                l = self.lps(f=f).length()
                 return self * f(self[-(l+1)::-1])
             elif side == 'left':
-                l = len(self.reversal().lps(f=f))
+                l = self.reversal().lps(f=f).length()
                 return f(self[:l-1:-1]) * self
             else:
                 raise ValueError, "side must be either 'left' or 'right' (not %s) " % side
 
-    def iterated_palindromic_closure(self, side='right', f=None):
-        r"""
-        Returns the iterated (`f`-)palindromic closure of self.
-        
-        INPUT:
-        
-        
-        -  ``side`` - 'right' or 'left' (default: 'right') the
-           direction of the closure
-        
-        -  ``f`` - involution (default: None) on the alphabet
-           of self. It must be something that WordMorphism's constructor
-           understands (dict, str, ...).
-        
-        
-        OUTPUT:
-        
-        
-        -  ``word`` - If f is None, the right iterated
-           palindromic closure of self; otherwise, the right iterated
-           f-palindromic closure of self. If side is 'left', the left
-           palindromic closure.
-        
-        
-        EXAMPLES::
-        
-            sage: W = Words('123')
-            sage: W('123').iterated_palindromic_closure()
-            word: 1213121
-            sage: W('123').iterated_palindromic_closure(side='left')
-            word: 3231323
-            sage: W('1').iterated_palindromic_closure()
-            word: 1
-            sage: W().iterated_palindromic_closure()
-            word: 
-            sage: W=Words('ab')                                                  
-            sage: W('ab').iterated_palindromic_closure(f='a->b,b->a')            
-            word: abbaab
-            sage: W('ab').iterated_palindromic_closure(f='a->b,b->a',side='left')
-            word: abbaab
-            sage: W('aab').iterated_palindromic_closure(f='a->b,b->a')            
-            word: ababbaabab
-            sage: W('aab').iterated_palindromic_closure(f='a->b,b->a',side='left')
-            word: abbaabbaab
-        
-        TESTS::
-        
-            sage: W('aab').iterated_palindromic_closure(f='a->b,b->a',side='leftt')
-            Traceback (most recent call last):
-            ...
-            ValueError: side must be either 'left' or 'right' (not leftt) 
-            sage: W('aab').iterated_palindromic_closure(f='a->b,b->b',side='left') 
-            Traceback (most recent call last):
-            ...
-            ValueError: f must be an involution
-        
-        REFERENCES:
-
-        - [1] A. de Luca, A. De Luca, Pseudopalindrome closure
-          operators in free monoids, Theoret. Comput. Sci. 362 (2006)
-          282-300.
-        """
-        if side == 'right':
-            par = self.parent()
-            return reduce(lambda r, s: (r*par([s])).palindromic_closure(f=f), 
-                            self, par())
-        elif side == 'left':
-            if f is None:
-                return self.reversal().iterated_palindromic_closure(f=f)
-            else:
-                from sage.combinat.words.morphism import WordMorphism
-                f = WordMorphism(f)
-                
-                if self not in f.domain():
-                    raise ValueError, "self must be in the domain of "\
-                                         +"the given involution"
-                
-                if not f.is_involution():
-                    raise ValueError, "f must be an involution"
-
-                return f(self).reversal().iterated_palindromic_closure(f=f)
-
-        else:
-            raise ValueError, "side must be either 'left' or 'right' (not %s) " % side
-
     def is_symmetric(self, f=None):
         r"""
-        Returns True if self is symmetric (or `f`-symmetric), and
+        Returns True if self is symmetric (or `f`-symmetric), and 
         False otherwise.
         
-        A word is *symmetric* (resp. *`f`-symmetric*) if it is the
-        product of two palindromes (resp. `f`-palindromes). See [1]
-        and [2].
-        
-        INPUT:
-        
-        
-        -  ``f`` - involution (default: None) on the alphabet
-           of self. It must be something that WordMorphism's constructor
-           understands (dict, str, ...).
-        
-        
-        OUTPUT:
-        
-        
-        -  ``boolean`` - If f is None, whether self is
-           symmetric; otherwise, whether self is `f`-symmetric.
-        
-        
-        EXAMPLES::
-        
-            sage: W = Words('ab')
+        A word is *symmetric* (resp. `f`-*symmetric*) if it is the 
+        product of two palindromes (resp. `f`-palindromes). See [1] and [2].
+
+        INPUT:
+
+        -  ``f`` - involution (default: None) on the alphabet of self. It must 
+           be callable on letters as well as words (e.g. WordMorphism).
+                             
+        EXAMPLES::
+
+            sage: W = Word
             sage: W('abbabab').is_symmetric()
             True
             sage: W('ababa').is_symmetric()
@@ -1898,500 +2999,35 @@
             False
             sage: W('aabbbaababba').is_symmetric()
             False
-            sage: W('aabbbaababba').is_symmetric('a->b,b->a')
-            True
-        
-        REFERENCES:
-
-        - [1] S. Brlek, S. Hamel, M. Nivat, C. Reutenauer, On the
-          Palindromic Complexity of Infinite Words, in J. Berstel, J.
-          Karhumaki, D. Perrin, Eds, Combinatorics on Words with
-          Applications, International Journal of Foundation of
-          Computer Science, Vol. 15, No. 2 (2004) 293-306.
-
-        - [2] A. de Luca, A. De Luca, Pseudopalindrome closure
-          operators in free monoids, Theoret.  Comput. Sci. 362 (2006)
-          282-300.
-        """
-        for i in range(len(self)):
+            sage: f = WordMorphism('a->b,b->a')
+            sage: W('aabbbaababba').is_symmetric(f)
+            True
+        
+        REFERENCES:        
+
+        -   [1] S. Brlek, S. Hamel, M. Nivat, C. Reutenauer, On the Palindromic
+            Complexity of Infinite Words, in J. Berstel, J. Karhumaki,
+            D. Perrin, Eds, Combinatorics on Words with Applications,
+            International Journal of Foundation of Computer Science, Vol. 15,
+            No. 2 (2004) 293--306.
+        -   [2] A. de Luca, A. De Luca, Pseudopalindrome closure operators
+            in free monoids, Theoret. Comput. Sci. 362 (2006) 282--300.
+        """
+        for i in range(self.length()):
             if self[:i].is_palindrome(f=f) and self[i:].is_palindrome(f=f):
                 return True
         return False
-
-    def is_square(self):
-        """
-        Returns True if self is a square, and False otherwise.
-        
-        EXAMPLES::
-        
-            sage: W = Words('123')
-            sage: W('1212').is_square()
-            True
-            sage: W('1213').is_square()
-            False
-            sage: W('12123').is_square()
-            False
-            sage: W().is_square()
-            True
-        """
-        if len(self) % 2 != 0:
-            return False
-        else:
-            l = len(self) / 2
-            return self[:l] == self[l:]
-
-    def is_square_free(self):
-        """
-        Returns True if self does not contain squares, and False
-        otherwise.
-        
-        EXAMPLES::
-        
-            sage: W = Words('123')
-            sage: W('12312').is_square_free()
-            True
-            sage: W('31212').is_square_free()
-            False
-            sage: W().is_square_free()
-            True
-        """
-        l = len(self)
-        if l < 2:
-            return True
-        suff = self
-        for i in xrange(0, l - 2):
-            for ll in xrange(2, l-i+1, 2):
-                if suff[:ll].is_square():
-                    return False
-            suff = suff[1:]
-        return True
-
-    def is_cube(self):
-        """
-        Returns True if self is a cube, and False otherwise.
-        
-        EXAMPLES::
-        
-            sage: W = Words('012')
-            sage: W('012012012').is_cube()
-            True
-            sage: W('01010101').is_cube()
-            False
-            sage: W().is_cube()
-            True
-            sage: W('012012').is_cube()
-            False
-        """
-        if len(self) % 3 != 0:
-            return False
-        l = len(self) / 3
-        return self[:l] == self[l:2*l] == self[2*l:]
-
-    def is_cube_free(self):
-        """
-        Returns True if self does not contain cubes, and False otherwise.
-        
-        EXAMPLES::
-        
-            sage: W = Words('123')
-            sage: W('12312').is_cube_free()
-            True
-            sage: W('32221').is_cube_free()
-            False
-            sage: W().is_cube_free()
-            True
-        """
-        l = len(self)
-        if l < 3: 
-            return True
-        suff = self
-        for i in xrange(0, l - 3):
-            for ll in xrange(3, l-i+1, 3):
-                if suff[:ll].is_cube():
-                    return False
-            suff = suff[1:]
-        return True
-        
-    def is_quasiperiodic(self):
-        """
-        Returns True if self is quasiperiodic, and False otherwise.
-        
-        A finite or infinite word `w` is *quasiperiodic* if it can
-        be constructed by concatenations and superpositions of one of its
-        proper factors `u`, which is called a *quasiperiod* of
-        `w`. See for instance [1], [2], and [3].
-        
-        EXAMPLES::
-        
-            sage: W = Words('abc')
-            sage: W('abaababaabaababaaba').is_quasiperiodic()
-            True
-            sage: W('abacaba').is_quasiperiodic()
-            False
-            sage: W('a').is_quasiperiodic()
-            False
-            sage: W().is_quasiperiodic()
-            False
-            sage: W('abaaba').is_quasiperiodic()
-            True
-        
-        REFERENCES:
-
-        - [1] A. Apostolico, A. Ehrenfeucht, Efficient detection of
-          quasiperiodicities in strings, Theoret. Comput. Sci. 119
-          (1993) 247-265.
-
-        - [2] S. Marcus, Quasiperiodic infinite words, Bull. Eur.
-          Assoc. Theor. Comput. Sci. 82 (2004) 170-174. [3] A. Glen,
-          F. Levé, G. Richomme, Quasiperiodic and Lyndon episturmian
-          words, Preprint, 2008, arXiv:0805.0730.
-        """
-        l = len(self)
-        if l <= 1:
-           return False
-        for i in range(1, l - 1):
-            return_lengths = [len(x) for x in self.return_words(self[:i])]
-            if return_lengths != []:
-               if (max(return_lengths) <= i and self[l-i:l] == self[:i]):
-                  return True
-        return False
-        
-    def _quasiperiods_list(self):
-        """
-        Returns the quasiperiods of self as a list ordered from shortest to
-        longest.
-        
-        EXAMPLES::
-        
-            sage: W = Words('abc')
-            sage: W('abaababaabaababaaba')._quasiperiods_list()
-            [word: aba, word: abaaba, word: abaababaaba]
-            sage: W('abaaba')._quasiperiods_list()
-            [word: aba]
-            sage: W('abacaba')._quasiperiods_list()
-            []
-        """
-        l = len(self)
-        if l <= 1:
-           return []
-        Q = []
-        for i in range(1, l - 1):
-            return_lengths = [len(x) for x in self.return_words(self[:i])]
-            if return_lengths != []:
-               if (max(return_lengths) <= i and self[l-i:l] == self[:i]):
-                  Q.append(self[:i])
-        return Q
-        
-    def quasiperiods(self):
-        """
-        Returns the set of quasiperiods of self.
-        
-        Let `w` be a finite or infinite word. A *quasiperiod* of
-        `w` is a proper factor `u` of `w` such that
-        the occurrences of `u` in `w` entirely cover
-        `w`, i.e., every position of `w` falls within some
-        occurrence of `u` in `w`. See for instance [1],
-        [2], and [3].
-        
-        TESTS::
-        
-            sage: W = Words('abc')
-            sage: W('abaababaabaababaaba').quasiperiods() == set([W('aba'), W('abaaba'), W('abaababaaba')])
-            True
-            sage: W('abaaba').quasiperiods() == set([W('aba')])
-            True
-            sage: W('abacaba').quasiperiods() == set([])
-            True
-        
-        REFERENCES:
-
-        - [1] A. Apostolico, A. Ehrenfeucht, Efficient detection of
-          quasiperiodicities in strings, Theoret. Comput. Sci. 119
-          (1993) 247-265.
-
-        - [2] S. Marcus, Quasiperiodic infinite words, Bull. Eur.
-          Assoc. Theor. Comput. Sci. 82 (2004) 170-174. [3] A. Glen,
-          F. Levé, G. Richomme, Quasiperiodic and Lyndon episturmian
-          words, Preprint, 2008, arXiv:0805.0730.
-        """
-        return set(self._quasiperiods_list())
-        
-    def commutes_with(self, other):
-        """
-        Returns True if self commutes with other, and False otherwise.
-        
-        EXAMPLES::
-        
-            sage: W = Words('12')
-            sage: W('12').commutes_with(W('12'))
-            True
-            sage: W('12').commutes_with(W('11'))
-            False
-            sage: W().commutes_with(W('21'))
-            True
-        """
-        return (self * other) == (other * self)
-        
-    def conjugate(self, pos):
-        """
-        Returns the conjugate at pos of self.
-        
-        pos can be any integer, the distance used is the modulo by the
-        length of self.
-        
-        EXAMPLES::
-        
-            sage: W = Words('12')
-            sage: W('12112').conjugate(1)
-            word: 21121
-            sage: W().conjugate(2)
-            word: 
-            sage: W('12112').conjugate(8)
-            word: 12121
-            sage: W('12112').conjugate(-1)
-            word: 21211
-        """
-        if self.is_empty():
-            return self
-        pos_mod = pos % len(self)
-        return self[pos_mod:] * self[:pos_mod]
-        
-    def _conjugates_list(self):
-        r"""
-        Returns the list of conjugates of self, ordered from the 0-th to
-        the (L-1)-st conjugate, where L is the length of self.
-        
-        TESTS::
-        
-            sage: W = Words('abc')
-            sage: W('cbbca')._conjugates_list()
-            [word: cbbca, word: bbcac, word: bcacb, word: cacbb, word: acbbc]
-            sage: W('abcabc')._conjugates_list()
-            [word: abcabc,
-             word: bcabca,
-             word: cabcab,
-             word: abcabc,
-             word: bcabca,
-             word: cabcab]
-            sage: W()._conjugates_list()
-            [word: ]
-            sage: W('a')._conjugates_list()
-            [word: a]
-        """
-        S = [self]
-        for i in range(1,len(self)):
-            S.append(self.conjugate(i))
-        return S
-        
-    def conjugates(self):
-        """
-        Returns the set of conjugates of self.
-        
-        TESTS::
-        
-            sage: W = Words('abc')
-            sage: W('cbbca').conjugates() == set([W('cacbb'),W('bbcac'),W('acbbc'),W('cbbca'),W('bcacb')])
-            True
-            sage: W('abcabc').conjugates() == set([W('abcabc'),W('bcabca'),W('cabcab')])
-            True
-            sage: W().conjugates() == set([W()])
-            True
-            sage: W('a').conjugates() == set([W('a')])
-            True
-        """
-        S = set([self])
-        for i in range(1,self.primitive_length()):
-            S.add(self.conjugate(i))
-        return S
-
-    def conjugate_position(self, other):
-        """
-        Returns the position where self is conjugate with other. Returns
-        None if there is no such position.
-        
-        EXAMPLES::
-        
-            sage: W = Words('123')
-            sage: W('12113').conjugate_position(W('31211'))
-            1
-            sage: W('12131').conjugate_position(W('12113')) is None
-            True
-            sage: W().conjugate_position(W('123')) is None
-            True
-        """
-        if len(self) != len(other):
-            return None
-        self, conj = self.coerce(other)
-        if self == conj:
-            return 0
-        for l in xrange(1, len(conj) - 1):
-            conj = conj.conjugate(1)
-            if self == conj:
-                return l
-        return None
-
-    def is_conjugate_with(self, other):
-        """
-        Returns True if self is a conjugate of other, and False otherwise.
-        
-        EXAMPLES::
-        
-            sage: W = Words('123')
-            sage: W('11213').is_conjugate_with(W('31121'))
-            True
-            sage: W().is_conjugate_with(W('123'))
-            False
-            sage: W('112131').is_conjugate_with(W('11213'))
-            False
-            sage: W('12131').is_conjugate_with(W('11213'))
-            True
-        """
-        return self.conjugate_position(other) is not None
-
-    def is_cadence(self, seq):
-        """
-        Returns True if seq is a cadence of self, and False otherwise.
-        
-        A *cadence* is an increasing sequence of indexes that all map to
-        the same letter.
-        
-        EXAMPLES::
-        
-            sage: W = Words('123')
-            sage: W('121132123').is_cadence([0, 2, 6])
-            True
-            sage: W('121132123').is_cadence([0, 1, 2])
-            False
-            sage: W('121132123').is_cadence([])
-            True
-        """
-        if len(seq) == 0:
-            return True
-        try:
-            it = iter(self)
-            s = islice(it, seq[0], None).next()
-            for i in xrange(1, len(seq)):
-                steps = seq[i] - seq[i-1]
-                for n in xrange(steps-1): it.next()
-                if it.next() != s:
-                    return False
-        except StopIteration:
-            return False
-        return True
-
-    def longest_common_prefix(self, other):
-        """
-        Returns the longest common prefix of self and other.
-        
-        EXAMPLES::
-        
-            sage: W = Words('0123456789')
-            sage: w=W('12345')
-            sage: y=W('1236777')
-            sage: w.longest_common_prefix(y)
-            word: 123
-            sage: w.longest_common_prefix(w)
-            word: 12345
-            sage: y.longest_common_prefix(w)
-            word: 123
-            sage: y.longest_common_prefix(w)==w.longest_common_prefix(y)
-            True
-            sage: y.longest_common_prefix(y)==y
-            True
-            sage: W().longest_common_prefix(w)
-            word: 
-            sage: w.longest_common_prefix(W()) == w
-            False
-            sage: w.longest_common_prefix(W()) == W()
-            True
-            sage: w.longest_common_prefix(w[:3]) == w[:3]
-            True
-            sage: w.longest_common_prefix(w[:3]) == w
-            False
-            sage: Words('12')("11").longest_common_prefix(Words('1')("1"))
-            word: 1
-        """
-        self, other = self.coerce(other)
-        self_iter, other_iter = iter(self._word_content), iter(other._word_content)
-        i = 0
-        try:
-            while True:
-                if self_iter.next() != other_iter.next():
-                    return self[:i]
-                i += 1
-        except StopIteration:  # one iterator finished
-            if len(self) < len(other):
-                return self
-            else:
-                return other
-
-    def longest_common_suffix(self, other):
-        """
-        Returns the longest common suffix of self and other.
-        
-        EXAMPLES::
-        
-            sage: W = Words('0123456789')
-            sage: y = W('549332345')
-            sage: w = W('203945')
-            sage: w.longest_common_suffix(y)
-            word: 45
-            sage: w.longest_common_suffix(y.reversal())
-            word: 3945
-            sage: w.longest_common_suffix(W())
-            word: 
-            sage: W().longest_common_suffix(w)
-            word: 
-            sage: W().longest_common_suffix(W())
-            word: 
-            sage: w.longest_common_suffix(w[3:]) == w[3:]
-            True
-            sage: w.longest_common_suffix(w[3:]) == w
-            False
-        """
-        self, other = self.coerce(other)
-        i = 0
-        while(i < min(len(self), len(other)) and self._word_content[-(i+1)] == other._word_content[-(i+1)]):
-            i += 1
-        if i == 0:
-            return self.parent()()
-        return self[-i:]
-
-    def prefix_function_table(self):
-        """
-        Returns a vector containing the length of the proper
-        prefix-suffixes for all the non-empty prefixes of self.
-        
-        EXAMPLES::
-        
-            sage: W = Words('0123456789')
-            sage: W('121321').prefix_function_table()
-            [0, 0, 1, 0, 0, 1]
-            sage: W('1241245').prefix_function_table()
-            [0, 0, 0, 1, 2, 3, 0]
-            sage: W().prefix_function_table()
-            []
-        """
-        k = 0
-        res = list(repeat(0, len(self)))
-        for q in xrange(1, len(self)):
-            while k > 0 and self._word_content[k] != self._word_content[q]:
-                k = res[k-1]
-            if self._word_content[k] == self._word_content[q]:
-                k += 1
-            res[q] = k
-        return res
-
+        
     def length_border(self):
-        """
+        r"""
         Returns the length of the border of self.
         
-        The *border* of a word is the longest word that is both a proper
+        The *border* of a word is the longest word that is both a proper 
         prefix and a proper suffix of self.
         
         EXAMPLES::
-        
-            sage: W = Words('0123456789')
+
+            sage: W = Word
             sage: W('121').length_border()
             1
             sage: W('1').length_border()
@@ -2403,18 +3039,18 @@
             sage: W().length_border() is None
             True
         """
-        if len(self) == 0:
+        if self.is_empty():
             return None
         return self.prefix_function_table()[-1]
 
     def border(self):
-        """
+        r"""
         Returns the longest word that is both a proper prefix and a proper
         suffix of self.
         
         EXAMPLES::
-        
-            sage: W = Words('0123456789')
+
+            sage: W = Word
             sage: W('121212').border()
             word: 1212
             sage: W('12321').border()
@@ -2422,7 +3058,7 @@
             sage: W().border() is None
             True
         """
-        if len(self) == 0:
+        if self.is_empty():
             return None
         return self[:self.length_border()]
         
@@ -2430,14 +3066,13 @@
         r"""
         Returns the period of self.
         
-        Let `A` be an alphabet. An integer `p\geq 1` is a
-        *period* of a word `w=a_1a_2\cdots a_n` where
-        `a_i\in A` if `a_i=a_{i+p}` for
-        `i=1,\ldots,n-p`. The smallest period of `w` is
-        called *the* period of `w`. See Chapter 1 of [1].
-        
-        EXAMPLES::
-        
+        Let `A` be an alphabet. An integer `p\geq 1` is a *period* of a 
+        word `w=a_1a_2\cdots a_n` where `a_i\in A` if `a_i=a_{i+p}` for 
+        `i=1,\ldots,n-p`. The smallest period of `w` is called *the* 
+        period of `w`. See Chapter 1 of [1].
+ 
+        EXAMPLES::
+
             sage: Word('aba').minimal_period()
             2
             sage: Word('abab').minimal_period()
@@ -2454,33 +3089,30 @@
             1       
             sage: Word().minimal_period()
             1 
-        
-        REFERENCES:
-
-        - [1] M. Lothaire, Algebraic Combinatorics On Words, vol.  90
-          of Encyclopedia of Mathematics and its Applications,
-          Cambridge University Press, U.K., 2002.
+ 
+        REFERENCES:
+
+        -   [1] M. Lothaire, Algebraic Combinatorics On Words, vol. 90 of
+            Encyclopedia of Mathematics and its Applications, Cambridge
+            University Press, U.K., 2002.
         """
         if self.is_empty():
             return 1
-        return len(self)-self.length_border()
+        return self.length()-self.length_border()
 
     def order(self):
         r"""
         Returns the order of self.
-        
-        Let `p(w)` be the period of a word `w`. The
-        positive rational number `|w|/p(w)` is the *order* of
-        `w`. See Chapter 8 of [1].
-        
-        OUTPUT:
-        
-        
-        -  ``rational`` - the order
-        
-        
-        EXAMPLES::
-        
+                
+        Let `p(w)` be the period of a word `w`. The positive rational number 
+        `|w|/p(w)` is the *order* of `w`. See Chapter 8 of [1].
+        
+        OUTPUT:
+
+            rational -- the order
+ 
+        EXAMPLES::
+
             sage: Word('abaaba').order()
             2
             sage: Word('ababaaba').order()
@@ -2491,25 +3123,30 @@
             2
             sage: Word().order()
             0
-        
-        REFERENCES:
-
-        - [1] M. Lothaire, Algebraic Combinatorics On Words, vol.  90
-          of Encyclopedia of Mathematics and its Applications,
-          Cambridge University Press, U.K., 2002.
+
+        REFERENCES:
+
+        -   [1] M. Lothaire, Algebraic Combinatorics On Words, vol. 90 of
+            Encyclopedia of Mathematics and its Applications, Cambridge
+            University Press, U.K., 2002.
         """
         from sage.rings.rational import Rational
-        return Rational((len(self),self.minimal_period()))
+        return Rational((self.length(),self.minimal_period()))
 
     def critical_exponent(self):
         r"""
         Returns the critical exponent of self.
         
-        The *critical exponent* of a word is the supremum of the order of
+        The *critical exponent* of a word is the supremum of the order of 
         all its (finite) factors. See [1].
-        
-        EXAMPLES::
-        
+
+        .. note::
+
+            The implementation here uses the suffix tree to enumerate all the 
+            factors. It should be improved.
+
+        EXAMPLES::
+
             sage: Word('aaba').critical_exponent()
             2
             sage: Word('aabaa').critical_exponent()
@@ -2522,21 +3159,21 @@
             3/2
             sage: words.ThueMorseWord()[:20].critical_exponent()
             2
-        
-        REFERENCES:
-
-        - [1] F. Dejean. Sur un théorème de Thue. J.  Combinatorial
-          Theory Ser. A 13:90–99, 1972.
-        """
-        return max(map(FiniteWord_over_OrderedAlphabet.order, self.factor_iterator()))
+
+        REFERENCES:
+
+        -   [1] F. Dejean. Sur un théorème de Thue. J. Combinatorial Theory 
+            Ser. A 13:90–99, 1972.
+        """
+        return max(map(FiniteWord_class.order, self.factor_iterator()))
 
     def is_overlap(self):
-        """
+        r"""
         Returns True if self is an overlap, and False otherwise.
         
         EXAMPLES::
-        
-            sage: W = Words('0123456789')
+
+            sage: W = Word
             sage: W('12121').is_overlap()
             True
             sage: W('123').is_overlap()
@@ -2550,23 +3187,23 @@
             sage: W().is_overlap()
             False
         """
-        if len(self) == 0:
-            return False
-        return self.length_border() > len(self)/2
+        if self.length() == 0:
+            return False
+        return self.length_border() > self.length()/2
 
     def primitive_length(self):
-        """
+        r"""
         Returns the length of the primitive of self.
         
         EXAMPLES::
-        
-            sage: W = Words('0123456789')
+
+            sage: W = Word
             sage: W('1231').primitive_length()
             4
             sage: W('121212').primitive_length()
             2
         """
-        l = lu = len(self)
+        l = lu = self.length()
         if l == 0:
             return 0
         p = self.prefix_function_table()
@@ -2576,29 +3213,29 @@
                 return lu - l
 
     def is_primitive(self):
-        """
+        r"""
         Returns True if self is primitive, and False otherwise.
         
-        A finite word `w` is *primitive* if it is not a positive
-        integer power of a shorter word.
-        
-        EXAMPLES::
-        
-            sage: W = Words('0123456789')
+        A finite word `w` is *primitive* if it is not a positive integer 
+        power of a shorter word.
+            
+        EXAMPLES::
+
+            sage: W = Word
             sage: W('1231').is_primitive()
             True
             sage: W('111').is_primitive()
             False
         """
-        return len(self) == self.primitive_length()
+        return self.length() == self.primitive_length()
 
     def primitive(self):
-        """
+        r"""
         Returns the primitive of self.
         
         EXAMPLES::
-        
-            sage: W = Words('0123456789')
+
+            sage: W = Word
             sage: W('12312').primitive()
             word: 12312
             sage: W('121212').primitive()
@@ -2607,18 +3244,16 @@
         return self[:self.primitive_length()]
 
     def exponent(self):
-        """
+        r"""
         Returns the exponent of self.
-        
-        OUTPUT:
-        
-        
-        -  ``integer`` - the exponent
-        
-        
-        EXAMPLES::
-        
-            sage: W = Words('0123456789')
+
+        OUTPUT:
+
+            integer -- the exponent
+        
+        EXAMPLES::
+
+            sage: W = Word
             sage: W('1231').exponent()
             1
             sage: W('121212').exponent()
@@ -2626,160 +3261,419 @@
             sage: W().exponent()
             0
         """
-        if len(self) == 0:
+        if self.length() == 0:
             return 0
-        return len(self) / self.primitive_length()
-        
-    def colored_vector(self, x=0, y=0, width='default', height=1, cmap='hsv', thickness=1):
-        r"""
-        Returns a vector (Graphics object) illustrating self. Each letter
-        is represented by a colored rectangle. There is a unique color for
-        each letter of the alphabet.
-        
-        INPUT:
-        
-        
-        -  ``x`` - (default: 0) bottom left x-coordinate of
-           the vector
-        
-        -  ``y`` - (default: 0) bottom left y-coordinate of
-           the vector
-        
-        -  ``width`` - (default: 'default') width of the
-           vector. By default, the width is the length of self.
-        
-        -  ``height`` - (default: 1) height of the vector
-        
-        -  ``thickness`` - (default: 1) thickness of the
-           contour
-        
-        -  ``cmap`` - (default: 'hsv') color map; type: 
-           ``import matplotlib.cm; matplotlib.cm.datad.keys()``
-           for available colormap names.
-        
-        
-        OUTPUT: Graphics
-        
-        EXAMPLES::
-        
-            sage: Word(range(20)).colored_vector()                
-        
-        ::
-        
-            sage: Word(range(100)).colored_vector(0,0,10,1)
-        
-        ::
-        
-            sage: Words(range(100))(range(10)).colored_vector()
-        
-        ::
-        
-            sage: w = Word('abbabaab')
-            sage: w.colored_vector()
-        
-        ::
-        
-            sage: w.colored_vector(cmap='autumn')
-        
-        TESTS::
-        
-            sage: Word(range(100)).colored_vector(cmap='jolies')
-            Traceback (most recent call last):
-            ...
-            RuntimeError: Color map jolies not known
-            sage: Word(range(100)).colored_vector(cmap='__doc__')
-            Traceback (most recent call last):
-            ...
-            RuntimeError: Color map __doc__ not known
-        """
-        #Recognize the color map
-        import matplotlib.cm as cm
-        from matplotlib.colors import LinearSegmentedColormap as C
-        key_error = False
+        return self.length() / self.primitive_length()
+
+    def is_subword_of(self, other):
+        r"""
+        Returns True is self is a subword of other, and False otherwise.
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W().is_subword_of(W('123'))
+            True
+            sage: W('123').is_subword_of(W('3211333213233321'))
+            True
+            sage: W('321').is_subword_of(W('11122212112122133111222332'))
+            False
+        """
+        its = iter(self)
         try:
-            mpl_cmap = cm.__dict__[cmap]
-        except KeyError:
-            key_error = True
-
-        if key_error or not isinstance(mpl_cmap, C):
-            possibilities = ', '.join([str(x) for x in cm.__dict__.keys() if \
-                                       isinstance(cm.__dict__[x], C)])
-            import sage.misc.misc
-            sage.misc.misc.verbose("The possible color maps include: %s"%possibilities, level=0)
-            raise RuntimeError, "Color map %s not known"%cmap
-
-        #Drawing the colored vector...
-        from sage.plot.plot import polygon,line
-
-        #The default width of the vector
-        if width == 'default':
-            width = len(self)
-
-        #The black frame of the vector
-        ymax = y + height
-        L = [(x,y), (x+width,y), (x+width,ymax), (x,ymax), (x,y)]
-        rep = line(L, rgbcolor=(0,0,0), thickness=thickness)
-
-        #base : the width of each rectangle 
-        base = width / float(len(self))
-
-        #A colored rectangle for each letter
-        xp = x
-        dim = float(self.parent().size_of_alphabet())
-        for i in self._word_content:
-            xq = xp + base
-            L = [(xp,y), (xq,y), (xq,ymax), (xp,ymax) ]
-            rgbcolor = mpl_cmap( i / dim ) [:3]
-            rep += polygon(L, rgbcolor = rgbcolor)
-            xp = xq
-        rep.axes(False)
-        return rep
-
+            s = its.next()
+            for e in other:
+                if s == e:
+                    s = its.next()
+            else:
+                return False
+        except StopIteration:
+            return True
+
+    def is_lyndon(self):
+        r"""
+        Returns True if self is a Lyndon word, and False otherwise.
+        
+        A *Lyndon word* is a non-empty word that is lexicographically
+        smaller than all of its proper suffixes for the given order
+        on its alphabet. That is, `w` is a Lyndon word if `w` is non-empty
+        and for each factorization `w = uv` (with `u`, `v` both non-empty),
+        we have `w < v`.
+            
+        Equivalently, `w` is a Lyndon word iff `w` is a non-empty word that is
+        lexicographically smaller than all of its proper conjugates for the
+        given order on its alphabet.
+        
+        See for instance [1].
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('123132133').is_lyndon()
+            True
+            sage: W().is_lyndon()
+            True
+            sage: W('122112').is_lyndon()
+            False
+        
+        REFERENCES:
+
+        -   [1] M. Lothaire, Combinatorics On Words, vol. 17 of Encyclopedia
+            of Mathematics and its Applications, Addison-Wesley, Reading,
+            Massachusetts, 1983.
+        """
+        if self.is_empty():
+            return True
+        it = enumerate(self)
+        s = it.next()[1]
+        cmp_fcn = self._parent.cmp_letters
+        for (i, e) in it:
+            # if s < e ....
+            if cmp_fcn(s,e) < 0:
+                continue
+            if not self.lex_less(self[i:]):
+                return False
+        return True
+        
+    def _duval_algorithm(self):
+        r"""
+        TESTS::
+
+            sage: Word('010010010001000')._duval_algorithm()
+            (01.001.001.0001)
+            sage: Word('122113112212')._duval_algorithm()
+            (122.113.112212)
+        
+        REFERENCES:
+
+        -   [1] J.-P. Duval, Factorizing words over an ordered alphabet,
+            J. Algorithms 4 (1983), no. 4, 363--381.
+        """
+        t = Factorization()
+        cm = self
+        c = iter(cm.to_integer_word())
+        cc = iter(cm.to_integer_word())
+        cc.next()
+        i = 0
+        d = 1
+        j = k = 1
+        l = len(cm)
+
+        while k < l:
+            c, c_s = tee(c)
+            c_s = c_s.next()
+            cc, cc_s = tee(cc)
+            cc_s = cc_s.next()
+            if c_s < cc_s:
+                cc.next()
+                k += 1
+                j = k
+                d = k - i
+                c = iter(cm.to_integer_word())
+            elif c_s == cc_s:
+                cc.next()
+                k += 1
+                if (k - j) == d:
+                    j = k
+                    c = iter(cm.to_integer_word())
+                else:
+                    c.next()
+            else:
+                i += d
+                while i <= j:
+                    i += d
+                    t.append(cm[:d])
+                    cm = cm[d:]
+                c = iter(cm.to_integer_word())
+                cc = iter(cm.to_integer_word())
+                cc.next()
+                i = j
+                j += 1
+                k = j
+                d = 1
+        i += d
+        while i <= j:
+            i += d
+            t.append(cm[:d])
+            cm = cm[d:]
+        return t
+        
+    def lyndon_factorization(self):
+        r"""
+        Returns the Lyndon factorization of self.
+        
+        The *Lyndon factorization* of a finite word `w` is the unique
+        factorization of `w` as a non-increasing product of Lyndon words,
+        i.e., `w = l_1\cdots l_n` where each `l_i` is a Lyndon word and
+        `l_1\geq \cdots \geq l_n`. See for instance [1].
+            
+        OUTPUT:
+
+            list -- the list of factors obtained
+        
+        EXAMPLES::
+
+            sage: Word('010010010001000').lyndon_factorization()
+            (01.001.001.0001.0.0.0)
+            sage: Words('10')('010010010001000').lyndon_factorization()
+            (0.10010010001000)
+            sage: Word('abbababbaababba').lyndon_factorization()
+            (abb.ababb.aababb.a)
+            sage: Words('ba')('abbababbaababba').lyndon_factorization()
+            (a.bbababbaaba.bba)
+
+        TESTS::
+
+            sage: Word('01').lyndon_factorization()
+            (01)
+            sage: Words('10')('01').lyndon_factorization()
+            (0.1)
+            sage: lynfac = Word('abbababbaababba').lyndon_factorization()
+            sage: [x.is_lyndon() for x in lynfac]
+            [True, True, True, True]
+            sage: lynfac = Words('ba')('abbababbaababba').lyndon_factorization()
+            sage: [x.is_lyndon() for x in lynfac]
+            [True, True, True]
+        
+        REFERENCES:
+
+        -   [1] J.-P. Duval, Factorizing words over an ordered alphabet,
+            J. Algorithms 4 (1983) 363--381.
+        """
+        tab = self._duval_algorithm()
+        l = sum(len(x) for x in tab)
+        if l < self.length():
+            tab += self[l:]._duval_algorithm()
+        return tab
+
+    def inversions(self):
+        r"""
+        Returns a list of the inversions of self. An inversion is a pair
+        (i,j) of non-negative integers i < j such that self[i] > self[j].
+
+        EXAMPLES::
+
+            sage: Word([1,2,3,2,2,1]).inversions()
+            [[1, 5], [2, 3], [2, 4], [2, 5], [3, 5], [4, 5]]
+            sage: Words([3,2,1])([1,2,3,2,2,1]).inversions()
+            [[0, 1], [0, 2], [0, 3], [0, 4], [1, 2]]
+            sage: Word('abbaba').inversions()
+            [[1, 3], [1, 5], [2, 3], [2, 5], [4, 5]]
+            sage: Words('ba')('abbaba').inversions()
+            [[0, 1], [0, 2], [0, 4], [3, 4]]
+        """
+        inversion_list = []
+        cmp_fcn = self._parent.cmp_letters
+        for (i1, letter1) in enumerate(self):
+            for (i2, letter2) in enumerate(self[i1+1:]):
+                if cmp_fcn(letter1, letter2) > 0:
+                    inversion_list.append([i1,i1+i2+1])
+        return inversion_list
+
+    # TODO: This function should be defined for words of integers, but it
+    # naturally is defined over an alphabet with a rank function....
+    def degree(self, weights=None):
+        r"""
+        Returns the weighted degree of self, where the weighted degree of
+        each letter in the ordered alphabet is given by weights, which
+        defaults to [1, 2, 3, ...].
+
+        INPUTS:
+
+        -  ``weights`` - a list or tuple, or a dictionary keyed by the
+           letters occurring in self.
+        
+        EXAMPLES::
+
+            sage: Word([1,2,3]).degree()
+            6
+            sage: Word([3,2,1]).degree()
+            6
+            sage: Words("ab")("abba").degree()
+            6
+            sage: Words("ab")("abba").degree([0,2])
+            4
+            sage: Words("ab")("abba").degree([-1,-1])
+            -4
+            sage: Words("ab")("aabba").degree([1,1])
+            5
+            sage: Words([1,2,4])([1,2,4]).degree()
+            6
+            sage: Word([1,2,4]).degree()
+            7
+            sage: Word("aabba").degree({'a':1,'b':2})
+            7
+            sage: Word([0,1,0]).degree({0:17,1:0})
+            34
+        """
+        if isinstance(weights, dict):
+            deg = 0
+            for a in self:
+                deg += weights[a]
+            return deg
+
+        if hasattr(self._parent._alphabet, "rank"):
+            rank_fcn = self._parent._alphabet.rank
+            deg = 0
+            if weights is None:
+                rank = {}
+                for a in self:
+                    if a not in rank:
+                        rank[a] = rank_fcn(a)
+                    deg += rank[a]+1
+            elif isinstance(weights, (list,tuple)):
+                rank = {}
+                for a in self:
+                    if a not in rank:
+                        rank[a] = rank_fcn(a)
+                    deg += weights[rank[a]]
+            return deg
+
+        if all(x in ZZ for x in self):
+            return sum(self)
+
+        raise TypeError, "degree is not defined for your word"
+
+    def deg_lex_less(self, other, weights=None):
+        r"""
+        Returns True if self is degree lexicographically less than other,
+        and False otherwise. The weight of each letter in the ordered
+        alphabet is given by weights, which defaults to [1, 2, 3, ...].
+        
+        EXAMPLES::
+
+            sage: WF = Word
+            sage: WF([1,2,3]).deg_lex_less(WF([1,3,2]))
+            True
+            sage: WF([3,2,1]).deg_lex_less(WF([1,2,3]))
+            False
+            sage: W = Words(range(5))
+            sage: W([1,2,4]).deg_lex_less(W([1,3,2]))
+            False
+            sage: WF("abba").deg_lex_less(WF("abbb"), dict(a=1,b=2))
+            True
+            sage: WF("abba").deg_lex_less(WF("baba"), dict(a=1,b=2))
+            True
+            sage: WF("abba").deg_lex_less(WF("aaba"), dict(a=1,b=2))
+            False
+            sage: WF("abba").deg_lex_less(WF("aaba"), dict(a=1,b=0))
+            True
+        """
+        deg_self = self.degree(weights)
+        deg_other = other.degree(weights)
+        if deg_self != deg_other:
+            return deg_self < deg_other
+        return self.lex_less(other)
+
+    def inv_lex_less(self, other):
+        r"""
+        Returns True if self is inverse lexicographically less than other.
+
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W([1,2,4]).inv_lex_less(W([1,3,2]))
+            False
+            sage: W([3,2,1]).inv_lex_less(W([1,2,3]))
+            True
+        """
+        if self.length() != len(other):
+            return self.length() < len(other)
+        return self.reversal() < other.reversal()
+
+    def deg_inv_lex_less(self,other,weights=None):
+        r"""
+        Returns True if the word self is degree inverse lexicographically
+        less than other.
+
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W([1,2,4]).deg_inv_lex_less(W([1,3,2]))
+            False
+            sage: W([3,2,1]).deg_inv_lex_less(W([1,2,3]))
+            True
+        """
+        d1 = self.degree(weights)
+        d2 = other.degree(weights)
+        if d1 != d2:
+            return d1 < d2
+        return self.inv_lex_less(other)
+
+    def rev_lex_less(self,other):
+        r"""
+        Returns True if the word self is reverse
+        lexicographically less than other.
+
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W([1,2,4]).rev_lex_less(W([1,3,2]))
+            True
+            sage: W([3,2,1]).rev_lex_less(W([1,2,3]))
+            False
+        """
+        if self.length() != len(other):
+            return self.length() > len(other)
+        return self.reversal() > other.reversal()
+
+    def deg_rev_lex_less(self, other, weights=None):
+        r"""
+        Returns True if self is degree reverse
+        lexicographically less than other.
+
+        EXAMPLES::
+
+            sage: Word([3,2,1]).deg_rev_lex_less(Word([1,2,3]))
+            False
+            sage: W = Word
+            sage: W([1,2,4]).deg_rev_lex_less(W([1,3,2]))
+            False
+            sage: W([1,2,3]).deg_rev_lex_less(W([1,2,4]))
+            True
+        """
+        d1 = self.degree(weights)
+        d2 = other.degree(weights)
+        if d1 != d2:
+            return d1 < d2
+        return self.rev_lex_less(other)
+
+    ###########################################################################
+    ##### DEPRECATION WARNINGS ################################################
+    ##### Added July 2009 #####################################################
+    ###########################################################################
     def last_position_table(self):
-        """
-        Returns a table (of size 256) that contains the last position of
-        each letter in self. The letters not present in the word will have
-        a position of None.
-        
-        EXAMPLES::
-        
-            sage: Words('01234')('1231232').last_position_table()
-            [-1, 3, 6, 5, -1]
-        """
-        res = [-1]*self.size_of_alphabet()
-        for (i, s) in izip(count(), self._word_content):
-            res[s] = i
-        return res
-
-    def good_suffix_table(self):
-        """
-        Returns a table of the maximum skip you can do in order not to miss
-        a possible occurrence of self in a word.
-        
-        This is a part of the Boyer-Moore algorithm to find factors. See
-        [1].
-        
-        EXAMPLES::
-        
-            sage: W = Words('0123456789')
-            sage: W('121321').good_suffix_table()
-            [5, 5, 5, 5, 3, 3, 1]
-            sage: W('12412').good_suffix_table()
-            [3, 3, 3, 3, 3, 1]
-        
-        REFERENCES:
-
-        - [1] R.S. Boyer, J.S. Moore, A fast string searching
-          algorithm, Communications of the ACM 20 (1977) 762-772.
-        """
-        l = len(self)
-        p = self.reversal().prefix_function_table()
-        res = [l - p[-1]]*(l+1)
-        for i in xrange(1, l+1):
-            j = l - p[i - 1]
-            if res[j] > (i - p[i-1]):
-                res[j] = i - p[i-1]
-        return res
+        r"""
+        Returns a dictionary that contains the last position of each letter
+        in self.
+        
+        EXAMPLES::
+
+            sage: Word('1231232').last_position_table()
+            doctest:1: DeprecationWarning: last_position_table is deprecated, use last_position_dict instead!
+            {'1': 3, '3': 5, '2': 6}
+        """
+        from sage.misc.misc import deprecation
+        deprecation("last_position_table is deprecated, use last_position_dict instead!")
+        lpd = self.last_position_dict()
+        if self.parent().size_of_alphabet() in ZZ:
+            return [lpd.get(a,-1) for a in self.parent().alphabet()]
+        return lpd
+
+    def last_position_dict(self):
+        r"""
+        Returns a dictionary that contains the last position of each letter
+        in self.
+        
+        EXAMPLES::
+
+            sage: Word('1231232').last_position_dict()
+            {'1': 3, '3': 5, '2': 6}
+        """
+        d = {}
+        for (i, letter) in enumerate(self):
+            d[letter] = i
+        return d
 
     def _pos_in(self, other, p):
         r"""
@@ -2787,26 +3681,26 @@
         position p in other.
         
         EXAMPLES::
-        
-            sage: W = Words('123')
-            sage: W('12')._pos_in(W('131231'), 2)
-            2
-            sage: W('12')._pos_in(W('131231'), 3) is None
-            True
-            sage: W('32')._pos_in(W('131231'), 0) is None
-            True
-        """
-        lf = len(self)
+
+            sage: Word('12')._pos_in(Word('131231'), 2)
+            2
+            sage: Word('12')._pos_in(Word('131231'), 3) is None
+            True
+            sage: Word('32')._pos_in(Word('131231'), 0) is None
+            True
+        """
+        lf = self.length()
         lm = len(other)
         if lf == 0 or lm == 0:
             return None
-        occ = self.last_position_table()
+        occ = self.last_position_dict()
         suff = self.good_suffix_table()
         s = p
         while s <= lm - lf:
             for j in xrange(lf-1, -1, -1):
-                if self._word_content[j] != other._word_content[s+j]:
-                    s += max(suff[j + 1], j - occ[other._word_content[s+j]])
+                a = other[s+j]
+                if self[j] != a :
+                    s += max(suff[j + 1], j - occ.get(a,-1))
                     break
             else:
                 return s
@@ -2814,47 +3708,72 @@
 
     def first_pos_in(self, other):
         r"""
-        Returns the position of the first occurrence of self in other, or
-        None if self is not a factor of other.
-        
-        EXAMPLES::
-        
-            sage: W = Words('0123456789')
-            sage: W('12').first_pos_in(W('131231'))
-            2
-            sage: W('32').first_pos_in(W('131231')) is None
-            True
-        """
-        self, other = self.coerce(other)
+        Returns the position of the first occurrence of self in other,
+        or None if self is not a factor of other.
+        
+        EXAMPLES::
+
+            sage: Word('12').first_pos_in(Word('131231'))
+            2
+            sage: Word('32').first_pos_in(Word('131231')) is None
+            True
+        """
         return self._pos_in(other, 0)
 
+    ###########################################################################
+    ##### DEPRECATION WARNINGS ################################################
+    ##### Added July 2009 #####################################################
+    ###########################################################################
     def is_factor_of(self, other):
         r"""
         Returns True if self is a factor of other, and False otherwise.
         
         EXAMPLES::
-        
-            sage: W = Words('0123456789')
-            sage: W('2113').is_factor_of(W('123121332131233121132123'))
-            True
-            sage: W('321').is_factor_of(W('1231241231312312312'))
+
+            sage: u = Word('2113')
+            sage: w = Word('123121332131233121132123')
+            sage: u.is_factor_of(w)
+            doctest:1: DeprecationWarning: is_factor_of is deprecated, use is_factor instead!
+            True
+            sage: u = Word('321')
+            sage: w = Word('1231241231312312312')
+            sage: u.is_factor_of(w)
+            False
+        """
+        from sage.misc.misc import deprecation
+        deprecation("is_factor_of is deprecated, use is_factor instead!")
+        return self.is_factor(other)
+
+    def is_factor(self, other):
+        r"""
+        Returns True if self is a factor of other, and False otherwise.
+        
+        EXAMPLES::
+
+            sage: u = Word('2113')
+            sage: w = Word('123121332131233121132123')
+            sage: u.is_factor(w)
+            True
+            sage: u = Word('321')
+            sage: w = Word('1231241231312312312')
+            sage: u.is_factor(w)
             False
         """
         return self.first_pos_in(other) is not None
 
     def factor_occurrences_in(self, other):
         r"""
-        Returns an iterator over all occurrences (including overlapping
-        ones) of self in other in their order of appearance.
-        
-        EXAMPLES::
-        
-            sage: W = Words('123')
-            sage: list(W('121').factor_occurrences_in(W('121213211213')))
+        Returns an iterator over all occurrences (including overlapping ones)
+        of self in other in their order of appearance.
+        
+        EXAMPLES::
+
+            sage: u = Word('121')
+            sage: w = Word('121213211213')
+            sage: list(u.factor_occurrences_in(w))
             [0, 2, 8]
         """
-        self, other = self.coerce(other)
-        if len(self) == 0:
+        if self.length() == 0:
             raise NotImplementedError, "undefined value"
         p = self._pos_in(other, 0)
         while p is not None:
@@ -2863,11 +3782,12 @@
 
     def nb_factor_occurrences_in(self, other):
         r"""
-        Returns the number of times self appears as a factor in other.
-        
-        EXAMPLES::
-        
-            sage: W = Words('123')
+        Returns the number of times self appears as a factor
+        in other.
+        
+        EXAMPLES::
+
+            sage: W = Word
             sage: W().nb_factor_occurrences_in(W('123'))
             Traceback (most recent call last):
             ...
@@ -2877,44 +3797,21 @@
             sage: W('321').nb_factor_occurrences_in(W('11233231231311233221123'))
             0
         """
-        return len_it(self.factor_occurrences_in(other))
-
-    def is_subword_of(self, other):
-        """
-        Returns True is self is a subword of other, and False otherwise.
-        
-        EXAMPLES::
-        
-            sage: W = Words('123')
-            sage: W().is_subword_of(W('123'))
-            True
-            sage: W('123').is_subword_of(W('3211333213233321'))
-            True
-            sage: W('321').is_subword_of(W('11122212112122133111222332'))
-            False
-        """
-        self, other = self.coerce(other)
-        its = iter(self._word_content)
-        try:
-            s = its.next()
-            for e in other._word_content:
-                if s == e:
-                    s = its.next()
-            else:
-                return False
-        except StopIteration:
-            return True
+        n = 0
+        for _ in self.factor_occurrences_in(other):
+            n += 1
+        return n
 
     def nb_subword_occurrences_in(self, other):
         r"""
         Returns the number of times self appears in other as a subword.
         
         EXAMPLES::
-        
-            sage: W = Words('1234')
+
+            sage: W = Word
             sage: W().nb_subword_occurrences_in(W('123'))
             Traceback (most recent call last):
-              ...
+            ...
             NotImplementedError: undefined value
             sage: W('123').nb_subword_occurrences_in(W('1133432311132311112'))
             11
@@ -2923,8 +3820,7 @@
             sage: W('3').nb_subword_occurrences_in(W('122332112321213'))
             4
         """
-        self, other = self.coerce(other)
-        ls = len(self)
+        ls = self.length()
         if ls == 0:
             raise NotImplementedError, "undefined value"
         elif ls == 1:
@@ -2947,16 +3843,14 @@
 
     def _return_words_list(self, fact):
         r"""
-        Returns the return words as a list in the order they appear in the
-        word.
-        
-        TESTS::
-        
-            sage: W = Words('abc')
+        Returns the return words as a list in the order they appear in the word.
+        
+        TESTS::
+
+            sage: W = Word
             sage: W('baccabccbacbca')._return_words_list(W('b'))
             [word: bacca, word: bcc, word: bac]
         """
-        self, fact = self.coerce(fact)
         i = fact.first_pos_in(self)
         if i is None:
             return []
@@ -2974,52 +3868,50 @@
         r"""
         Returns the set of return words of fact in self.
         
-        This is the set of all factors starting by the given factor and
-        ending just before the next occurrence of this factor. See [1] and
-        [2].
-        
-        EXAMPLES::
-        
-            sage: W = Words('123')
-            sage: W('21331233213231').return_words(W('2')) == set([W('21331'), W('233'), W('213')])
-            True
-            sage: W().return_words(W('213')) == set()
-            True
-            sage: W('121212').return_words(W('1212')) == set([W('12')])
-            True
-        
-        REFERENCES:
-
-        - [1] F. Durand, A characterization of substitutive sequences
-          using return words, Discrete Math. 179 (1998) 89-101.
-
-        - [2] C. Holton, L.Q. Zamboni, Descendants of primitive
-          substitutions, Theory Comput. Syst. 32 (1999) 133-157.
+        This is the set of all factors starting by the given factor and ending
+        just before the next occurrence of this factor. See [1] and [2].
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('21331233213231').return_words(W('2')) 
+            set([word: 213, word: 21331, word: 233])
+            sage: W().return_words(W('213'))
+            set([])
+            sage: W('121212').return_words(W('1212'))
+            set([word: 12])
+        
+        REFERENCES:
+
+        -   [1] F. Durand, A characterization of substitutive sequences using
+            return words, Discrete Math. 179 (1998) 89-101.
+        -   [2] C. Holton, L.Q. Zamboni, Descendants of primitive substitutions,
+            Theory Comput. Syst. 32 (1999) 133-157.
         """
         return set(self._return_words_list(fact))
 
     def complete_return_words(self, fact):
-        """
+        r"""
         Returns the set of complete return words of fact in self.
         
-        This is the set of all factors starting by the given factor and
-        ending just after the next occurrence of this factor. See for
-        instance [1].
-        
-        EXAMPLES::
-        
-            sage: W = Words('123')
-            sage: W('21331233213231').complete_return_words(W('2')) == set([W('213312'), W('2332'), W('2132')])
-            True
-            sage: W('').complete_return_words(W('213')) == set()
-            True
-            sage: W('121212').complete_return_words(W('1212')) == set([W('121212')])
-            True
-        
-        REFERENCES:
-
-        - [1] J. Justin, L. Vuillon, Return words in Sturmian and
-          episturmian words, Theor. Inform. Appl. 34 (2000) 343-356.
+        This is the set of all factors starting by the given factor and ending
+        just after the next occurrence of this factor. See for instance [1].
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: s = W('21331233213231').complete_return_words(W('2')) 
+            sage: sorted(s)
+            [word: 2132, word: 213312, word: 2332]
+            sage: W('').complete_return_words(W('213'))
+            set([])
+            sage: W('121212').complete_return_words(W('1212'))
+            set([word: 121212])
+
+        REFERENCES:
+
+        -   [1] J. Justin, L. Vuillon, Return words in Sturmian and
+            episturmian words, Theor. Inform. Appl. 34 (2000) 343--356.
         """
         i = fact.first_pos_in(self)
         if i is None:
@@ -3034,648 +3926,172 @@
             j = fact.first_pos_in(w)
         return res
 
-    def return_words_derivate(self, fact, W=None):
-        r"""
-        Returns the word generated by mapping a letter to each occurrence
-        of the return words for the given factor dropping any dangling
-        prefix and suffix.
-        
-        The optional set of words parameter must be over an alphabet that
-        contains as much letters as there are different return words in
-        self, otherwise there will be some breakage in the function. The
-        default value for this parameter always respects this property. The
-        letters are attributed to the words in the order they are
-        discovered.
-        
-        EXAMPLES::
-        
-            sage: Words('123')('12131221312313122').return_words_derivate(Words('1')('1'))
+    def return_words_derivate(self, fact):
+        r"""
+        Returns the word generated by mapping a letter to each occurrence of 
+        the return words for the given factor dropping any dangling prefix and 
+        suffix. See for instance [1].
+        
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('12131221312313122').return_words_derivate(W('1'))
             word: 123242
-        
-        REFERENCES:
-
-        - [1] F. Durand, A characterization of substitutive
-          sequences using return words, Discrete Math. 179 (1998) 89-101.
-        """
-        self, fact = self.coerce(fact)
+            
+        REFERENCES:
+
+        -   [1] F. Durand, A characterization of substitutive sequences using
+            return words, Discrete Math. 179 (1998) 89--101.
+        """
         idx = 0
         tab = {}
-        ret = map(lambda w: tab.setdefault(w, len(tab)) + 1, self._return_words_list(fact))
-        if W is None:
-            W = Words(xrange(1, len(tab)+1)) 
-        return W(ret)
-
-    def delta(self):
-        """
-        Returns the delta equivalent of self.
-        
-        This is the word composed of the length of consecutive runs of the
-        same letter in a given word.
-        
-        EXAMPLES::
-        
-            sage: W = Words('0123456789')
-            sage: W('22112122').delta()
-            word: 22112
-            sage: W('555008').delta()
-            word: 321
-            sage: W().delta()
-            word:
-        """
-        if len(self) == 0:
-            return Words([])()
-        ss = self[0]
-        c = 0
-        v = list()
-        max_c = 0
-        for s in self:
-            if s == ss:
-                c += 1
-                if c > max_c:
-                    max_c = c
-            else:
-                v.append(c)
-                ss = s
-                c = 1
-        v.append(c)
-        return Words(xrange(1, max_c+1))(v)
-
-    def delta_inv(self, W=None, s=None):
-        """
-        Returns the inverse of the delta operator applied to self.
-        
-        The letters in the returned word will start at the specified letter
-        or the first one if None is specified (the default). The default
-        alphabet is [1, 2].
-        
-        EXAMPLES::
-        
-            sage: W = Words([1, 2])
-            sage: W([2, 2, 1, 1]).delta_inv()
-            word: 112212
-            sage: W([1, 1, 1, 1]).delta_inv(Words('123'))
-            word: 1231
-            sage: W([2, 2, 1, 1, 2]).delta_inv(s=2)
-            word: 22112122
-        """
-        if not all(imap(isint, self.alphabet())):
-            raise ValueError, "delta_inv() can only be applied to word composed of integer letters"
-        if W is None:
-            W = Words([1, 2])
-        if len(self) == 0:
-            return W()
-        if not is_Words(W):
-            raise TypeError, "W must be an instance of Words"
-        if s is None:
-            s = W.alphabet().unrank(0)
-        if s not in W.alphabet():
-            raise ValueError, "starting letter not in alphabet"
-        v = []
-        
-        p = W.alphabet().rank(s)
-        al = cycle(imap(W.alphabet().unrank, chain(xrange(p, W.size_of_alphabet()), xrange(p))))
-        al.next()
-        for e in self:
-            v += ([s] * e)
-            s = al.next()
-        return W(v)
-
-    def delta_derivate(self, W=None):
-        """
-        Returns the derivative under delta for self.
-        
-        EXAMPLES::
-        
-            sage: W = Words('12')
-            sage: W('12211').delta_derivate()
-            word: 22
-            sage: W('1').delta_derivate(Words([1]))
-            word: 1
-            sage: W('2112').delta_derivate()
-            word: 2
-            sage: W('2211').delta_derivate()
-            word: 22
-            sage: W('112').delta_derivate()
-            word: 2
-            sage: W('11222').delta_derivate(Words([1, 2, 3]))
-            word: 3
-        """
-        d = self.delta()
-        if len(d) == 0:
-            return d
-        if W is None:
-            W = d.parent()
-        if d[0] != W.alphabet().last():
-            d = d[1:]
-        if d[-1] != W.alphabet().last():
-            d = d[:-1]
-        return d
-
-    def delta_derivate_left(self, W=None):
-        """
-        Returns the derivative under delta for self.
-        
-        EXAMPLES::
-        
-            sage: W = Words('12')
-            sage: W('12211').delta_derivate_left()
-            word: 22
-            sage: W('1').delta_derivate_left(Words([1]))
-            word: 1
-            sage: W('2112').delta_derivate_left()
-            word: 21
-            sage: W('2211').delta_derivate_left()
-            word: 22
-            sage: W('112').delta_derivate_left()
-            word: 21
-            sage: W('11222').delta_derivate_left(Words([1, 2, 3]))
-            word: 3
-        """
-        d = self.delta()
-        if len(d) == 0:
-            return d
-        if W is None:
-            W = d.parent()
-        if d[0] != W.alphabet().last():
-            d = d[1:]
-        return d
-
-    def delta_derivate_right(self, W=None):
-        """
-        Returns the right derivative under delta for self.
-        
-        EXAMPLES::
-        
-            sage: W = Words('12')
-            sage: W('12211').delta_derivate_right()
-            word: 122
-            sage: W('1').delta_derivate_right(Words([1]))
-            word: 1
-            sage: W('2112').delta_derivate_right()
-            word: 12
-            sage: W('2211').delta_derivate_right()
-            word: 22
-            sage: W('112').delta_derivate_right()
-            word: 2
-            sage: W('11222').delta_derivate_right(Words([1, 2, 3]))
-            word: 23
-        """
-        d = self.delta()
-        if len(d) == 0:
-            return d
-        if W is None:
-            W = d.parent()
-        if d[-1] != W.alphabet().last():
-            d = d[:-1]
-        return d
-
-    def phi(self):
-        r"""
-        Applies the phi function to self and returns the result.
-        
-        See for instance [1] and [2].
-        
-        INPUT:
-        
-        
-        -  ``self`` - must be a word over integers
-        
-        
-        OUTPUT:
-        
-        
-        -  ``word`` - the result of the phi function
-        
-        
-        EXAMPLES::
-        
-            sage: W = Words([1, 2])
-            sage: W([2, 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 2]).phi()
-            word: 222222
-            sage: W().phi()
-            word: 
-            sage: W([2, 1, 2, 2, 1, 2, 2, 1, 2, 1]).phi()
-            word: 212113
-        
-        REFERENCES:
-
-        - [1] S. Brlek, A. Ladouceur, A note on differentiable
-          palindromes, Theoret. Comput. Sci. 302 (2003) 167-178.
-
-        - [2] S. Brlek, S. Dulucq, A. Ladouceur, L. Vuillon,
-          Combinatorial properties of smooth infinite words,
-          Theoret. Comput. Sci. 352 (2006) 306-317.
-        """
-        if self.is_empty():
-            return self
-        m = self
-        v = []
-        s_max = 0
-        while len(m) > 1:
-            v.append(m[0])
-            if m[0] > s_max:
-                s_max = m[0]
-            m = m.delta()
-        v.append(m[0])
-        if m[0] > s_max:
-            s_max = m[0]
-        return Words(xrange(1, s_max+1))(v)
-
-    def phi_inv(self, W=None):
-        r"""
-        Applied the inverse of the phi function and returns the result.
-        
-        INPUT:
-        
-        
-        -  ``self`` - must be a word over the integers
-        
-        -  ``W`` - the set of words of the result (must also be
-           over the integers)
-        
-        
-        OUTPUT:
-        
-        
-        -  ``word`` - the inverse of the phi function
-        
-        
-        EXAMPLES::
-        
-            sage: W = Words([1, 2])
-            sage: W([2, 2, 2, 2, 1, 2]).phi_inv()
-            word: 22112122
-            sage: W([2, 2, 2]).phi_inv(Words([2, 3]))
-            word: 2233
-        """
-        if W is None:
-            W = self.parent()
-        if self.is_empty():
-            return W()
-        v = self.parent()((self[-1],))
-        for i in xrange(len(self) - 2, -1, -1):
-            v = v.delta_inv(W, self[i])
-        return v
-
-    def _phi_inv_tab(self, tab):
-        r"""
-        Specialized version of phi_inv() for long or incremental words.
-        
-        TESTS::
-        
-            sage: Words([1, 2])([1, 1, 2, 2])._phi_inv_tab([2])
-            word: 12211
-        """
-        res = self.delta_inv(s=tab[0])
-        res = res[1:]
-        for i in xrange(1, len(tab)):
-            res = res.delta_inv(s=tab[i])
-        return res
-
-    def is_smooth_prefix(self):
-        r"""
-        Returns True if self is the prefix of a smooth word, and False
-        otherwise.
-        
-        Let `A_k = \{1, \ldots ,k\}`, `k \geq 2`. An
-        infinite word `w` in `A_k^\omega` is said to be
-        *smooth* if and only if for all positive integers `m`,
-        `\Delta^m(w)` is in `A_k^\omega`, where
-        `\Delta(w)` is the word obtained from `w` by
-        composing the length of consecutive runs of the same letter in
-        `w`. See for instance [1] and [2].
-        
-        INPUT:
-        
-        
-        -  ``self`` - must be a word over the integers to get
-           something other than False
-        
-        
-        OUTPUT:
-        
-        
-        -  ``boolean`` - whether self is a smooth prefix or
-           not
-        
-        
-        EXAMPLES::
-        
-            sage: W = Words([1, 2])
-            sage: W([1, 1, 2, 2, 1, 2, 1, 1]).is_smooth_prefix()
-            True
-            sage: W([1, 2, 1, 2, 1, 2]).is_smooth_prefix()
-            False
-        
-        REFERENCES:
-
-        - [1] S. Brlek, A. Ladouceur, A note on differentiable
-          palindromes, Theoret. Comput. Sci. 302 (2003) 167-178.
-
-        - [2] S.  Brlek, S. Dulucq, A. Ladouceur, L. Vuillon,
-          Combinatorial properties of smooth infinite words,
-          Theoret. Comput. Sci. 352 (2006) 306-317.
-        """
-        m = self
-        while len(m) > 1:
-            m = m.delta_derivate_right()
-            if m not in self.parent():
-                return False
-        return True
-
-    def is_lyndon(self):
-        """
-        Returns True if self is a Lyndon word, and False otherwise.
-        
-        A *Lyndon word* is a non-empty word that is lexicographically
-        smaller than all of its proper suffixes for the given order on its
-        alphabet. That is, `w` is a Lyndon word if `w` is
-        non-empty and for each factorization `w = uv` (with
-        `u`, `v` both non-empty), we have `w < v`.
-        
-        Equivalently, `w` is a Lyndon word iff `w` is a
-        non-empty word that is lexicographically smaller than all of its
-        proper conjugates for the given order on its alphabet.
-        
-        See for instance [1].
-        
-        EXAMPLES::
-        
-            sage: W = Words('0123456789')
-            sage: W('123132133').is_lyndon()
-            True
-            sage: W().is_lyndon()
-            True
-            sage: W('122112').is_lyndon()
-            False
-        
-        REFERENCES:
-
-        - [1] M. Lothaire, Combinatorics On Words, vol. 17 of
-          Encyclopedia of Mathematics and its Applications,
-          Addison-Wesley, Reading, Massachusetts, 1983.
-        """
-        if len(self) == 0:
-            return True
-        s = self._word_content[0]
-        for (e, i) in izip(self[1:]._word_content, count(1)):
-            if s < e:
-                continue
-            if not self < self[i:]:
-                return False
-        return True
-        
-    def BWT(self):
-        """
-        Returns the Burrows-Wheeler Transform (BWT) of self.
-        
-        The *Burrows-Wheeler transform* of a finite word `w` is
-        obtained from `w` by first listing the conjugates of
-        `w` in lexicographic order and then concatenating the final
-        letters of the conjugates in this order. See [1].
-        
-        EXAMPLES::
-        
-            sage: W = Words('abc')
-            sage: W('abaccaaba').BWT()
-            word: cbaabaaca
-            sage: W('abaab').BWT()
-            word: bbaaa
-            sage: W('bbabbaca').BWT()
-            word: cbbbbaaa
-            sage: W('aabaab').BWT()
-            word: bbaaaa
-            sage: Word().BWT()
-            word: 
-            sage: W('a').BWT()
-            word: a
-        
-        REFERENCES:
-
-        - [1] M. Burrows, D.J. Wheeler, "A block-sorting lossless
-          data compression algorithm", HP Lab Technical Report, 1994,
-          available at
-          http://www.hpl.hp.com/techreports/Compaq-DEC/SRC-RR-124.html
-        """
-        if self.is_empty():
-           return self
-        conjugates = self._conjugates_list()
-        conjugates.sort()
-        return self.parent()([x[len(x)-1] for x in conjugates])
-
-    def _duval_algorithm(self):
-        """
-        TESTS::
-        
-            sage: Words('01')('010010010001000')._duval_algorithm()
-            (01.001.001.0001)
-            sage: Words('123')('122113112212')._duval_algorithm()
-            (122.113.112212)
-        
-        REFERENCES:
-
-        - [1] J.-P. Duval, Factorizing words over an ordered
-          alphabet, J. Algorithms 4 (1983), no. 4, 363-381.
-        """
-        t = Factorization()
-        cm = self
-        c = iter(cm._word_content)
-        cc = iter(cm._word_content)
-        cc.next()
-        i = 0
-        d = 1
-        j = k = 1
-        l = len(cm)
-
-        while k < l:
-            c, c_s = peek_it(c)
-            cc, cc_s = peek_it(cc)
-            if c_s < cc_s:
-                cc.next()
-                k += 1
-                j = k
-                d = k - i
-                c = iter(cm._word_content)
-            elif c_s == cc_s:
-                cc.next()
-                k += 1
-                if (k - j) == d:
-                    j = k
-                    c = iter(cm._word_content)
-                else:
-                    c.next()
-            else:
-                i += d
-                while i <= j:
-                    i += d
-                    t.append(cm[:d])
-                    cm = cm[d:]
-                c = iter(cm._word_content)
-                cc = iter(cm._word_content)
-                cc.next()
-                i = j
-                j += 1
-                k = j
-                d = 1
-        i += d
-        while i <= j:
-            i += d
-            t.append(cm[:d])
-            cm = cm[d:]
-        return t
-        
-    def lyndon_factorization(self):
-        r"""
-        Returns the Lyndon factorization of self.
-        
-        The *Lyndon factorization* of a finite word `w` is the
-        unique factorization of `w` as a non-increasing product of
-        Lyndon words, i.e., `w = l_1\cdots l_n` where each
-        `l_i` is a Lyndon word and
-        `l_1\geq \cdots \geq l_n`. See for instance [1].
-        
-        OUTPUT:
-        
-        
-        -  ``list`` - the list of factors obtained
-        
-        
-        EXAMPLES::
-        
-            sage: Words('01')('010010010001000').lyndon_factorization()
-            (01.001.001.0001.0.0.0)
-            sage: Words('10')('010010010001000').lyndon_factorization()
-            (0.10010010001000)
-            sage: Words('ab')('abbababbaababba').lyndon_factorization()
-            (abb.ababb.aababb.a)
-            sage: Words('ba')('abbababbaababba').lyndon_factorization()
-            (a.bbababbaaba.bba)
-        
-        TESTS::
-        
-            sage: Words('01')('01').lyndon_factorization()
-            (01)
-            sage: Words('10')('01').lyndon_factorization()
-            (0.1)
-            sage: lynfac = Words('ab')('abbababbaababba').lyndon_factorization()
-            sage: map(lambda x:x.is_lyndon(), lynfac)
-            [True, True, True, True]
-            sage: lynfac = Words('ba')('abbababbaababba').lyndon_factorization()
-            sage: map(lambda x:x.is_lyndon(), lynfac)
-            [True, True, True]
-        
-        REFERENCES:
-
-        - [1] J.-P. Duval, Factorizing words over an ordered
-          alphabet, J. Algorithms 4 (1983) 363-381.
-        """
-        tab = self._duval_algorithm()
-        l = sum(imap(len, tab))
-        if l < len(self):
-            tab += self[l:]._duval_algorithm()
-        return tab
-
-    def standard_factorization(self):
-        r"""
-        Returns the standard factorization of self.
-        
-        The *standard factorization* of a word `w` is the unique
-        factorization: `w = uv` where `v` is the longest
-        proper suffix of `w` that qualifies as a Lyndon word.
-        
-        Note that if `w` is a Lyndon word with standard
-        factorization `w = uv`, then `u` and `v`
-        are also Lyndon words and `u < v`.
-        
-        See for instance [1] and [2].
-        
-        OUTPUT:
-        
-        
-        -  ``list`` - the list of factors
-        
-        
-        EXAMPLES::
-        
-            sage: Words('01')('0010110011').standard_factorization()
-            (001011.0011)
-            sage: Words('123')('1223312').standard_factorization()
-            (12233.12)
-        
-        REFERENCES:
-
-        - [1] K.-T. Chen, R.H. Fox, R.C. Lyndon, Free differential
-          calculus, IV. The quotient groups of the lower central
-          series, Ann. of Math. 68 (1958) 81-95.
-
-        - [2] J.-P. Duval, Factorizing words over an ordered alphabet,
-          J. Algorithms 4 (1983) 363-381.
-        """
-        suff = self[1:]
-        for l in xrange(1, len(self)):
-            pref = self[:l]
-            if pref.is_lyndon() and suff.is_lyndon():
-                return Factorization([pref, suff])
-            suff = suff[1:]
-        return Factorization([self, self.parent()()])
-
-    def standard_factorization_of_lyndon_factorization(self):
-        r"""
-        Returns the standard factorization of the Lyndon factorization of
-        self.
-        
-        OUTPUT:
-        
-        
-        -  ``list of lists`` - the factorization
-        
-        
-        EXAMPLES::
-        
-            sage: Words('123')('1221131122').standard_factorization_of_lyndon_factorization()
-            [(12.2), (1.13), (1.122)]
-        """
-        return map(FiniteWord_over_OrderedAlphabet.standard_factorization, self.lyndon_factorization())
-
+        ret = map(lambda w: tab.setdefault(w, len(tab)) + 1, \
+                                self._return_words_list(fact))
+        return Word(ret)
+
+    def is_quasiperiodic(self):
+        r"""
+        Returns True if self is quasiperiodic, and False otherwise.
+        
+        A finite or infinite word `w` is *quasiperiodic* if it can be
+        constructed by concatenations and superpositions of one of its proper 
+        factors `u`, which is called a *quasiperiod* of `w`. 
+        See for instance [1], [2], and [3].
+            
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('abaababaabaababaaba').is_quasiperiodic()
+            True
+            sage: W('abacaba').is_quasiperiodic()
+            False
+            sage: W('a').is_quasiperiodic()
+            False
+            sage: W().is_quasiperiodic()
+            False
+            sage: W('abaaba').is_quasiperiodic()
+            True
+            
+        REFERENCES:
+
+        -   [1] A. Apostolico, A. Ehrenfeucht, Efficient detection of
+            quasiperiodicities in strings, Theoret. Comput. Sci. 119 (1993)
+            247--265.
+        -   [2] S. Marcus, Quasiperiodic infinite words, Bull. Eur. Assoc.
+            Theor. Comput. Sci. 82 (2004) 170-174.
+        -   [3] A. Glen, F. Levé, G. Richomme, Quasiperiodic and Lyndon
+            episturmian words, Preprint, 2008, arXiv:0805.0730.
+        """
+        l = self.length()
+        if l <= 1:
+           return False
+        for i in range(1, l - 1):
+            return_lengths = [x.length() for x in self.return_words(self[:i])]
+            if return_lengths != []:
+               if (max(return_lengths) <= i and self[l-i:l] == self[:i]):
+                  return True
+        return False
+        
+    ###########################################################################
+    ##### DEPRECATION WARNINGS ################################################
+    ##### Added July 2009 #####################################################
+    ###########################################################################
+    def _quasiperiods_list(self):
+        r"""
+        Returns the quasiperiods of self as a list ordered from shortest to
+        longest.
+
+        EXAMPLES::
+
+            sage: W = Word
+            sage: l = W('abaababaabaababaaba')._quasiperiods_list()
+            doctest:1: DeprecationWarning: _quasiperiods_list is deprecated, use quasiperiods instead!
+            sage: l
+            [word: aba, word: abaaba, word: abaababaaba]
+        """
+        from sage.misc.misc import deprecation
+        deprecation("_quasiperiods_list is deprecated, use quasiperiods instead!")
+        return self.quasiperiods()
+
+    def quasiperiods(self):
+        r"""
+        Returns the quasiperiods of self as a list ordered from shortest to
+        longest.
+        
+        Let `w` be a finite or infinite word. A *quasiperiod* of `w` is a 
+        proper factor `u` of `w` such that the occurrences of `u` in `w` 
+        entirely cover `w`, i.e., every position of `w` falls within some 
+        occurrence of `u` in `w`. See for instance [1], [2], and [3].
+            
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('abaababaabaababaaba').quasiperiods()
+            [word: aba, word: abaaba, word: abaababaaba]
+            sage: W('abaaba').quasiperiods()
+            [word: aba]
+            sage: W('abacaba').quasiperiods()
+            []
+            
+        REFERENCES:
+
+        -   [1] A. Apostolico, A. Ehrenfeucht, Efficient detection of
+            quasiperiodicities in strings, Theoret. Comput. Sci. 119 (1993)
+            247--265.
+        -   [2] S. Marcus, Quasiperiodic infinite words, Bull. Eur. Assoc.
+            Theor. Comput. Sci. 82 (2004) 170-174.
+        -   [3] A. Glen, F. Levé, G. Richomme, Quasiperiodic and Lyndon
+            episturmian words, Preprint, 2008, arXiv:0805.0730.
+        """
+        l = self.length()
+        if l <= 1:
+           return []
+        Q = []
+        for i in range(1, l - 1):
+            return_lengths = [x.length() for x in self.return_words(self[:i])]
+            if return_lengths != []:
+               if (max(return_lengths) <= i and self[l-i:l] == self[:i]):
+                  Q.append(self[:i])
+        return Q
+        
     def crochemore_factorization(self):
         r"""
         Returns the Crochemore factorization of self as an ordered list of
         factors.
         
-        The *Crochemore factorization* of a finite word `w` is the
-        unique factorization: `(x_1, x_2, \ldots, x_n)` of
-        `w` with each `x_i` satisfying either: C1.
-        `x_i` is a letter that does not appear in
-        `u = x_1\ldots x_{i-1}`; C2. `x_i` is the
-        longest prefix of `v = x_i\ldots x_n` that also has an
-        occurrence beginning within `u = x_1\ldots x_{i-1}`. See
-        [1].
-        
-        This is not a very good implementation, and should be improved.
-        
-        EXAMPLES::
-        
-            sage: x = Words('ab')('abababb')
+        The *Crochemore factorization* of a finite word `w` is the unique
+        factorization: `(x_1, x_2, \ldots, x_n)` of `w` with each `x_i`
+        satisfying either:
+        C1. `x_i` is a letter that does not appear in `u = x_1\ldots x_{i-1}`;
+        C2. `x_i` is the longest prefix of `v = x_i\ldots x_n` that also
+        has an occurrence beginning within `u = x_1\ldots x_{i-1}`. See [1].
+            
+        .. note::
+
+            This is not a very good implementation, and should be improved.
+        
+        EXAMPLES::
+
+            sage: x = Word('abababb')
             sage: x.crochemore_factorization()
             (a.b.abab.b)
             sage: mul(x.crochemore_factorization()) == x
             True
-            sage: y = Words('abc')('abaababacabba')
+            sage: y = Word('abaababacabba')
             sage: y.crochemore_factorization()
             (a.b.a.aba.ba.c.ab.ba)
             sage: mul(y.crochemore_factorization()) == y
             True
-            sage: x = Words([0, 1])([0,1,0,1,0,1,1])
+            sage: x = Word([0,1,0,1,0,1,1])
             sage: x.crochemore_factorization()
             (0.1.0101.1)
             sage: mul(x.crochemore_factorization()) == x
             True
-        
-        REFERENCES:
-
-        - [1] M. Crochemore, Recherche linéaire d'un carré dans un
-          mot, C. R. Acad. Sci. Paris Sér. I Math. 296 (1983) 14
-          781-784.
+            
+        REFERENCES:
+
+        -   [1] M. Crochemore, Recherche linéaire d'un carré dans un mot,
+            C. R. Acad. Sci. Paris Sér. I Math. 296 (1983) 14 781--784.
         """
         c = Factorization([self[:1]])
         u = self[:sum(map(len,c))] # = x_1 ... x_{i-1}
@@ -3689,7 +4105,7 @@
             #     occurrence beginning within u = x_1...x_{i-1}.
                 xi = v
                 while True:
-                    if xi.first_pos_in(self) < len(u):
+                    if xi.first_pos_in(self) < u.length():
                         c.append(xi)
                         break
                     else:
@@ -3697,102 +4113,29 @@
             u = self[:sum(map(len,c))] # = x_1 ... x_{i-1}
             v = self[sum(map(len,c)):] # = x_i ... x_n
         return c
-        
-    def is_balanced(self, q=1):
-        r"""
-        Returns True if self is `q`-balanced, and False otherwise.
-        
-        A finite or infinite word `w` is said to be
-        *`q`-balanced* if for any two factors `u`,
-        `v` of `w` of the same length, the difference
-        between the number of `x`'s in each of `u` and
-        `v` is at most `q` for all letters `x` in
-        the alphabet of `w`. A `1`-balanced word is simply
-        said to be balanced. See for instance [1] and Chapter 2 of [2].
-        
-        INPUT:
-        
-        
-        -  ``q`` - integer (default 1), the balance level
-        
-        
-        OUTPUT:
-        
-        
-        -  ``boolean`` - the result
-        
-        
-        EXAMPLES::
-        
-            sage: Words('123')('1213121').is_balanced()
-            True
-            sage: Words('12')('1122').is_balanced()
-            False
-            sage: Words('123')('121333121').is_balanced()
-            False
-            sage: Words('123')('121333121').is_balanced(2)
-            False
-            sage: Words('123')('121333121').is_balanced(3)
-            True
-            sage: Words('12')('121122121').is_balanced()
-            False
-            sage: Words('12')('121122121').is_balanced(2)
-            True
-            sage: Words('12')('121122121').is_balanced(-1)
-            Traceback (most recent call last):
-            ...
-            TypeError: the balance level must be a positive integer
-            sage: Words('12')('121122121').is_balanced(0)
-            Traceback (most recent call last):
-            ...
-            TypeError: the balance level must be a positive integer
-            sage: Words('12')('121122121').is_balanced('a')
-            Traceback (most recent call last):
-            ...
-            TypeError: the balance level must be a positive integer
-        
-        REFERENCES:
-
-        - [1] J. Cassaigne, S. Ferenczi, L.Q. Zamboni, Imbalances
-          in Arnoux-Rauzy sequences, Ann. Inst. Fourier (Grenoble) 50 (2000)
-          1265-1276.
-
-        - [2] M. Lothaire, Algebraic Combinatorics On Words, vol.  90
-          of Encyclopedia of Mathematics and its Applications,
-          Cambridge University Press, U.K., 2002.
-        """
-        if not isint(q) or q <= 0:
-           raise TypeError, "the balance level must be a positive integer"
-        for i in xrange(2, len(self)):
-            tab = [None] * self.size_of_alphabet()
-            for j in xrange(len(tab)):
-                tab[j] = set()
-            for fact in self.factor_iterator(i):
-                for (n, sym) in izip(count(), self.alphabet()):
-                    tab[n].add(self.parent()(sym).nb_factor_occurrences_in(fact))
-            for t in tab:
-                if len(t) > q+1:
-                    return False
-        return True
-
+
+    ###########################################################################
+    ##### DEPRECATION WARNINGS ################################################
+    ##### Added July 2009 #####################################################
+    ###########################################################################
     def freq(self):
         r"""
         Returns a table of the frequencies of the letters in self.
         
         OUTPUT:
-        
-        
-        -  ``dict`` - letters associated to their frequency
-        
-        
-        EXAMPLES::
-        
-            sage: Words('123')('1213121').freq()    # keys appear in random order
+
+            dict -- letters associated to their frequency
+            
+        EXAMPLES::
+
+            sage: f = Word('1213121').freq()    
+            doctest:1: DeprecationWarning: freq is deprecated, use evaluation_dict instead!
+            sage: f # keys appear in random order
             {'1': 4, '2': 2, '3': 1}
-        
-        TESTS::
-        
-            sage: f = Words('123')('1213121').freq()
+            
+        TESTS::
+
+            sage: f = Word('1213121').freq()
             sage: f['1'] == 4
             True
             sage: f['2'] == 2
@@ -3800,371 +4143,121 @@
             sage: f['3'] == 1
             True
         """
-        res = dict()
-        for sym in self.alphabet():
-            res[sym] = 0
-        for s in self:
-            res[s] += 1
-        return res
-        
-    def parikh_vector(self):
-        """
-        Returns the Parikh vector of self, i.e., the vector containing the
-        number of occurrences of each letter, given in the order of the
-        alphabet.
-        
-        See also evaluation, which returns a list truncated after the last
-        nonzero entry.
-        
-        EXAMPLES::
-        
-            sage: Word('aabaa').parikh_vector()
-            [4, 1]
-            sage: Word('aabaacaccab').parikh_vector()
-            [6, 2, 3]
-            sage: Words('abc')('aabaa').parikh_vector()
-            [4, 1, 0]
-            sage: Word().parikh_vector()
-            []
-            sage: Word('a').parikh_vector()
-            [1]
-            sage: Words('abc')('a').parikh_vector()
-            [1, 0, 0]
-            sage: Words('ab')().parikh_vector()
-            [0, 0]
-            sage: Words('abc')().parikh_vector()
-            [0, 0, 0]
-            sage: Words('abcd')().parikh_vector()
-            [0, 0, 0, 0]
-        
-        TESTS::
-        
-            sage: P = Alphabet(name="positive integers")
-            sage: w = Words(P)(range(1,10))
-            sage: w.parikh_vector()
-            Traceback (most recent call last):
-            ...
-            TypeError: the alphabet is infinite; use evaluation() instead
-        """
-        n = self.parent().size_of_alphabet()
-        if not isinstance(n, (int,Integer)):
-            raise TypeError, "the alphabet is infinite; use evaluation() instead"
-        v = [0]*n
-        for c in self._word_content:
-            v[c] += 1
-        return v
-
-    def apply_morphism(self,morphism):
-        """
-        Returns the word obtained by applying the morphism to self.
-        
-        INPUT:
-        
-        
-        -  ``morphism`` - Can be an instance of WordMorphism,
-           or anything that can be used to construct one.
-        
-        
-        EXAMPLES::
-        
-            sage: w = Word("ab")
-            sage: d = {'a':'ab', 'b':'ba'}
-            sage: w.apply_morphism(d)
-            word: abba
-            sage: w.apply_morphism(WordMorphism(d))
-            word: abba
-        """
-        from sage.combinat.words.morphism import WordMorphism
-        if not isinstance(morphism, WordMorphism):
-            morphism = WordMorphism(morphism)
-        return morphism(self)
-
-    def count(self, letter):
-        """
-        Counts the number of occurrences of letter in self.
-        
-        EXAMPLES::
-        
-            sage: Words('ab')('abbabaab').count('a')
-            4
-        """
-        return self.parent()([letter]).nb_factor_occurrences_in(self)
-
-    def suffix_trie(self):
-        r"""
-        Returns the suffix trie of self.
-        
-        The *suffix trie* of a finite word `w` is a data structure
-        representing the factors of `w`. It is a tree whose edges
-        are labelled with letters of `w`, and whose leafs
-        correspond to suffixes of `w`.
-        
-        See sage.combinat.words.suffix_trees.SuffixTrie? for more
-        information.
-        
-        EXAMPLES::
-        
-            sage: w = Words("cao")("cacao")
-            sage: w.suffix_trie()
-            Suffix Trie of the word: cacao
-        
-        ::
-        
-            sage: w = Words([0,1])([0,1,0,1,1])
-            sage: w.suffix_trie()
-            Suffix Trie of the word: 01011
-        """
-        from sage.combinat.words.suffix_trees import SuffixTrie
-        return SuffixTrie(self)
-
-    def implicit_suffix_tree(self):
-        r"""
-        Returns the implicit suffix tree of self.
-        
-        The *suffix tree* of a word `w` is a compactification of
-        the suffix trie for `w`. The compactification removes all
-        nodes that have exactly one incoming edge and exactly one outgoing
-        edge. It consists of two components: a tree and a word. Thus,
-        instead of labelling the edges by factors of `w`, we can
-        labelled them by indices of the occurrence of the factors in
-        `w`.
-        
-        See sage.combinat.words.suffix_trees.ImplicitSuffixTree? for more
-        information.
-        
-        EXAMPLES::
-        
-            sage: w = Words("cao")("cacao")
-            sage: w.implicit_suffix_tree()
-            Implicit Suffix Tree of the word: cacao
-        
-        ::
-        
-            sage: w = Words([0,1])([0,1,0,1,1])
-            sage: w.implicit_suffix_tree()
-            Implicit Suffix Tree of the word: 01011
-        """
-        from sage.combinat.words.suffix_trees import ImplicitSuffixTree
-        return ImplicitSuffixTree(self)
-
-    def suffix_tree(self):
-        r"""
-        Alias for implicit_suffix_tree().
-        
-        EXAMPLES::
-        
-            sage: Words('ab')('abbabaab').suffix_tree()
-            Implicit Suffix Tree of the word: abbabaab
-        """
-        return self.implicit_suffix_tree()
-
-    def number_of_factors(self,n=None):
-        r"""
-        Counts the number of distinct factors of self.
-        
-        INPUT:
-        
-        
-        -  ``n`` - an integer, or None.
-        
-        
-        OUTPUT: If n is an integer, returns the number of distinct factors
-        of length n. If n is None, returns the total number of distinct
-        factors.
-        
-        EXAMPLES::
-        
-            sage: w = Words([1,2,3])([1,2,1,2,3])
-            sage: w.number_of_factors()
-            13
-            sage: map(w.number_of_factors, range(6))
-            [1, 3, 3, 3, 2, 1]
-        
-        ::
-        
-            sage: Words('123')('1213121').number_of_factors()
-            22
-            sage: Words('123')('1213121').number_of_factors(1)
-            3
-        
-        ::
-        
-            sage: Words('a')('a'*100).number_of_factors()
-            101
-            sage: Words('a')('a'*100).number_of_factors(77)
-            1
-        
-        ::
-        
-            sage: Words([])().number_of_factors()
-            1
-            sage: Words([])().number_of_factors(17)
-            0
-        
-        ::
-        
-            sage: blueberry = Word("blueberry")
-            sage: blueberry.number_of_factors()
-            43
-            sage: map(blueberry.number_of_factors, range(10))
-            [1, 6, 8, 7, 6, 5, 4, 3, 2, 1]
-        """
-        return self.suffix_tree().number_of_factors(n)
-
-    def factor_iterator(self,n=None):
-        r"""
-        Generates distinct factors of self.
-        
-        INPUT:
-        
-        
-        -  ``n`` - an integer, or None.
-        
-        
-        OUTPUT: If n is an integer, returns an iterator over all distinct
-        factors of length n. If n is None, returns an iterator generating
-        all distinct factors.
-        
-        EXAMPLES::
-        
-            sage: w = Words('123')('1213121')
-            sage: sorted( w.factor_iterator(0) )
-            [word: ]
-            sage: sorted( w.factor_iterator(10) )
-            []
-            sage: sorted( w.factor_iterator(1) )
-            [word: 1, word: 2, word: 3]
-            sage: sorted( w.factor_iterator(4) )
-            [word: 1213, word: 1312, word: 2131, word: 3121]
-            sage: sorted( w.factor_iterator() )
-            [word: , word: 1, word: 12, word: 121, word: 1213, word: 12131, word: 121312, word: 1213121, word: 13, word: 131, word: 1312, word: 13121, word: 2, word: 21, word: 213, word: 2131, word: 21312, word: 213121, word: 3, word: 31, word: 312, word: 3121]
-        
-        ::
-        
-            sage: u = Words([1,2,3])([1,2,1,2,3])
-            sage: sorted( u.factor_iterator(0) )
-            [word: ]
-            sage: sorted( u.factor_iterator(10) )
-            []
-            sage: sorted( u.factor_iterator(1) )
-            [word: 1, word: 2, word: 3]
-            sage: sorted( u.factor_iterator(5) )
-            [word: 12123]
-            sage: sorted( u.factor_iterator() )
-            [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]
-        
-        ::
-        
-            sage: xxx = Word("xxx")
-            sage: sorted( xxx.factor_iterator(0) )
-            [word: ]
-            sage: sorted( xxx.factor_iterator(4) )
-            []
-            sage: sorted( xxx.factor_iterator(2) )
-            [word: xx]
-            sage: sorted( xxx.factor_iterator() )
-            [word: , word: x, word: xx, word: xxx]
-        
-        ::
-        
-            sage: e = Word()
-            sage: sorted( e.factor_iterator(0) )
-            [word: ]
-            sage: sorted( e.factor_iterator(17) )
-            []
-            sage: sorted( e.factor_iterator() )
-            [word: ]
-        
-        TESTS::
-        
-            sage: type( Words('cao')('cacao').factor_iterator() )
-            <type 'generator'>
-        """
-        return self.suffix_tree().factor_iterator(n)
-
-    def factor_set(self):
-        r"""
-        Returns the set of factors of self.
-        
-        EXAMPLES::
-        
-            sage: Words('123')('1213121').factor_set()   # random
-            Set of elements of <generator object at 0xa8fde6c>
-            sage: sorted(  Words([1,2,3])([1,2,1,2,3]).factor_set()  )
-            [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]
-            sage: sorted(  Words("x")("xx").factor_set()  )
-            [word: , word: x, word: xx]
-            sage: set( Words([])().factor_set() )
-            set([word: ])
-        """
-        return Set(set(self.factor_iterator()))
+        from sage.misc.misc import deprecation
+        deprecation("freq is deprecated, use evaluation_dict instead!")
+        return self.evaluation_dict()
+
+    def evaluation_dict(self):
+        r"""
+        Returns a dictionary keyed by the letters occurring in self with
+        values the number of occurrences of the letter.
+
+        EXAMPLES::
+
+            sage: Word([2,1,4,2,3,4,2]).evaluation_dict()
+            {1: 1, 2: 3, 3: 1, 4: 2}
+            sage: Word('badbcdb').evaluation_dict()
+            {'a': 1, 'c': 1, 'b': 3, 'd': 2}
+            sage: Word().evaluation_dict()
+            {}
+        """
+        d = {}
+        for a in self:
+            d[a] = d.get(a,0) + 1
+        return d
+
+    def evaluation_sparse(self):
+        r"""
+        Returns a list representing the evaluation of self. The entries of
+        the list are two-element lists [a, n], where a is a letter
+        occurring in self and n is the number of occurrences of a in self.
+
+        EXAMPLES::
+
+            sage: Word([4,4,2,5,2,1,4,1]).evaluation_sparse()
+            [(1, 2), (2, 2), (4, 3), (5, 1)]
+            sage: Word("abcaccab").evaluation_sparse()
+            [('a', 3), ('c', 3), ('b', 2)]
+        """
+        return self.evaluation_dict().items()
+
+    def evaluation_partition(self):
+        r"""
+        Returns the evaluation of the word w as a partition.
+
+        EXAMPLES::
+
+            sage: Word("acdabda").evaluation_partition()
+            [3, 2, 1, 1]
+            sage: Word([2,1,4,2,3,4,2]).evaluation_partition()
+            [3, 2, 1, 1]
+        """
+        p = sorted(self.evaluation_dict().values(), reverse=True)
+        if 0 in p:
+            return Partition(p[:p.index(0)])
+        else:
+            return Partition(p)
 
     def overlap_partition(self, other, delay=0, p=None):
-        """
+        r"""
         Returns the partition of the alphabet induced by the equivalence
-        relation defined below.
-        
-        Let `u = u_0 u_1 \cdots u_{n-1}`,
-        `v = v_0v_1\cdots v_{m-1}` be two words on the alphabet
-        `A` where `u_i`, `v_j` are letters and
-        let `d` be an integer. We define a relation
-        `R_{u,v,d}\subset A \times A` by
-        `R_{u,v,d} = \{ (u_k, v_{k-d}) : 0 \leq k < n, 0\leq k-d < m \}`.
-        The equivalence relation returned is the symmetric, reflexive and
-        transitive closure of `R_{self,other,delay}\cup p`
-        (inspired from [1]).
-        
-        EXAMPLE ILLUSTRATING THE PRECEDENT DEFINITION: Let
-        `A = \{a, b, c, d, e, f, h, l, v \}`, `u=cheval`,
-        `v=abcdef` and `d=3`. Then `0 \leq k < 6`
-        and `0\leq k-3 < 6` implies that `3\leq k \leq 5`.
-        Then,
-
-        .. math::
-
-           R_{u,v,d} = \{ (u_3, v_0), (u_4, v_1), (u_5, v_2) \}
-                     = \{ (v, a), (a, b), (l, c) \}
-                     
-        These three couples correspond to the pairs of letters one above
-        the other in the following overlap::
-
-           cheval
-              abcdef
-
-        The symmetric, reflexive and transitive closure of `R_{u,v,d}`
-        defines the following partition of the alphabet `A`:
-
-        .. math::
-
-           \{\{a, b, v\}, \{c, l\}, \{d\}, \{e\}, \{f\}, \{h\}\}.
-        
-        INPUT:
-        
-        
+        relation obtained from the symmetric, reflexive and transitive 
+        closure of `R_{self,other,delay}\cup p` defined below.
+
+        Let `u = u_0 u_1 \cdots u_{n-1}`, `v = v_0v_1\cdots v_{m-1}` be two 
+        words on the alphabet `A` where `u_i, v_j \in A` are letters and 
+        let `d` be an integer. We define a relation 
+        `R_{u,v,d}\subseteq A \times A` by 
+        `R_{u,v,d} = \{ (u_k, v_{k-d}) : 0 \leq k < n, 0\leq k-d < m \}`.  
+        The equivalence relation obtained from `R` is inspired from [1].
+
+        EXAMPLE: 
+
+            Let `A = \{\tt{a}, \tt{b}, \tt{c}, \tt{d}, \tt{e}, \tt{f}, \tt{h},
+            \tt{l}, \tt{v} \}`, 
+            `s=\tt{cheval}, t=\tt{abcdef} \in A^*` and `d=3`. 
+            Then `0 \leq k < 6` and `0\leq k-3 < 6` implies that
+            `3\leq k \leq 5`. Then, 
+            `R_{s,t,d} = \{ (s_3, t_0), (s_4, t_1), (s_5, t_2) \} = \{ (\tt{v},
+            \tt{a}), (\tt{a}, \tt{b}), (\tt{l}, \tt{c}) \}`.
+            These three couples correspond to the pairs of letters one above 
+            the other in the following overlap :
+
+                    `\tt{cheval}`
+                       `\tt{abcdef}`
+
+            The symmetric, reflexive and transitive closure of `R_{s,t,d}`
+            defines the following partition of the alphabet `A`:
+            `\{\{\tt{a}, \tt{b}, \tt{v}\}, \{\tt{c}, \tt{l}\}, \{\tt{d}\},
+            \{\tt{e}\}, \{\tt{f}\}, \{\tt{h}\}\}`.
+
+        INPUT:
+
         -  ``other`` - word on the same alphabet as self
-        
         -  ``delay`` - integer
-        
-        -  ``p`` - Set (default: None), a partition of the
-           alphabet
-        
-        
-        OUTPUT:
-        
-        
-        -  ``p`` - Set, a set partition of the alphabet of self
-           and other.
-        
-        
-        EXAMPLES::
-        
+        -  ``p`` - Set (default: None), a partition of the alphabet
+
+        OUTPUT:
+
+        -  ``p`` - Set, a set partition of the alphabet of self and other.
+
+        EXAMPLES:
+
+        The above example::
+
             sage: W = Words('abcdefhlv')
             sage: cheval = W('cheval')
             sage: abcdef = W('abcdef')
             sage: p = cheval.overlap_partition(abcdef,3); p
             {{'f'}, {'e'}, {'d'}, {'a', 'b', 'v'}, {'c', 'l'}, {'h'}}
+
+        The same example with delay 2 ::
+
             sage: cheval.overlap_partition(abcdef,2,p)
             {{'f'}, {'a', 'c', 'b', 'e', 'd', 'v', 'l'}, {'h'}}
+
+        ::
+
             sage: W = Words('abcdef')
             sage: w = W('abc')
             sage: y = W('def')
@@ -4184,6 +4277,9 @@
             {{'f'}, {'e'}, {'d'}, {'b'}, {'a'}, {'c'}}
             sage: w.overlap_partition(y, 4)
             {{'f'}, {'e'}, {'d'}, {'b'}, {'a'}, {'c'}}
+
+        ::
+
             sage: W = Words(range(2))
             sage: w = W([0,1,0,1,0,1]); w
             word: 010101
@@ -4191,46 +4287,46 @@
             {{0}, {1}}
             sage: w.overlap_partition(w, 1)
             {{0, 1}}
-        
-        TESTS::
-        
-            sage: Word().overlap_partition(Word(),'yo')  
+
+        TESTS::
+
+            sage: empty = Word()
+            sage: empty.overlap_partition(empty, 'yo')  
             Traceback (most recent call last):
             ...
             TypeError: delay (type given: <type 'str'>) must be an integer
-            sage: Word().overlap_partition(Word(),2,'yo')
+            sage: empty.overlap_partition(empty,2,'yo')
             Traceback (most recent call last):
             ...
             TypeError: p(=yo) is not a Set
-            sage: Word('a').overlap_partition(Word('b'),0)
-            Traceback (most recent call last):
-            ...
-            TypeError: no coercion rule between Ordered Alphabet ['a'] and Ordered Alphabet ['b']
-        
-        REFERENCES:
-
-        - [1] S. Labbé, Propriétés combinatoires des
-          `f`-palindromes, Mémoire de maîtrise en Mathématiques,
-          Montréal, UQAM, 2008, 109 pages.
-        """
-        if not isint(delay):
+
+        REFERENCES:
+
+        -   [1] S. Labbé, Propriétés combinatoires des `f`-palindromes,  
+            Mémoire de maîtrise en Mathématiques, Montréal, UQAM, 2008, 
+            109 pages.
+        """
+        if not isinstance(delay, (int, Integer)):
             raise TypeError, \
                   "delay (type given: %s) must be an integer"%type(delay)
         elif delay < 0:
             return other.overlap_partition(self, -delay, p)
 
-        self, other = self.coerce(other)
+        alphabet = self.parent().alphabet()
 
         if p is None:
-            R = [[x] for x in self.alphabet()]
+            if self.parent().size_of_alphabet() is Infinity:
+                raise ValueError, 'cannot construct the default set partition of an infinite alphabet'
+            else:
+                R = [[x] for x in alphabet]
         else:
             if not is_Set(p):
                 raise TypeError, "p(=%s) is not a Set" % p
-            if Set(self.alphabet().list()) != reduce(lambda x,y:x.union(y), p):
+            if Set(alphabet.list()) != reduce(lambda x,y:x.union(y), p):
                 raise TypeError, "p(=%s) is not a partition of the alphabet" % p
             R = map(list,p)
 
-        d, n, m = delay, len(self), len(other)
+        d, n, m = delay, self.length(), other.length()
         S = [(self[k], other[k-d]) for k in range(max(0,d), min(n,m+d))]
 
         for (a,b) in S:
@@ -4245,169 +4341,57 @@
                 R += [set_a + set_b]
         return Set(map(Set, R))
 
-    def evaluation(self):
-        r"""
-        Returns a list a where a[i] is the number of occurrences in self of
-        the i-th letter in self.alphabet().
-        
-        NOTE: This is slightly different from self.parikh_vector() in that
-        it truncates the list after the last nonzero output.
-        
-        EXAMPLES::
-        
-            sage: Words('ab')('aabaa').evaluation()
-            [4, 1]
-            sage: Words('bac')('aabaa').evaluation()
-            [1, 4]
-            sage: Words('bca')('aabaa').evaluation()
-            [1, 0, 4]
-            sage: Words('abc')('aabaa').evaluation()
-            [4, 1]
-            sage: Word('aabaacaccab').evaluation()
-            [6, 2, 3]
-            sage: Word().evaluation()
-            []
-            sage: Words('abcde')('badbcdb').evaluation()
-            [1, 3, 1, 2]
-            sage: Word([1,2,2,1,3]).evaluation()
-            [2, 2, 1]
-            sage: P = Alphabet(name="positive integers")
-            sage: Words(P)([]).evaluation()
-            []
-        """
-        if list(self) == []:
-            return []
-        d = self.evaluation_dict()
-        m = max(self, key=self.alphabet().rank)
-        ev = []
-        for a in self.alphabet():
-            ev.append(d.get(a,0))
-            if a == m:
-                break
-        return ev
-
-    def evaluation_dict(self):
-        r"""
-        Returns a dictionary keyed by the letters occurring in self with
-        values the number of occurrences of the letter.
-        
-        EXAMPLES::
-        
-            sage: Word([2,1,4,2,3,4,2]).evaluation_dict()
-            {1: 1, 2: 3, 3: 1, 4: 2}
-            sage: Word('badbcdb').evaluation_dict()
-            {'a': 1, 'c': 1, 'b': 3, 'd': 2}
-            sage: Word().evaluation_dict()
-            {}
-        """
-        d = {}
-        alphabet = self.alphabet()
-        for c in self._word_content:
-            a = alphabet.unrank(c)
-            d[a] = d.setdefault(a,0) + 1
-        return d
-
-    def evaluation_sparse(self):
-        r"""
-        Returns a list representing the evaluation of self. The entries of
-        the list are two-element lists [a, n], where a is a letter
-        occurring in self and n is the number of occurrences of a in self.
-        
-        EXAMPLES::
-        
-            sage: Word([4,4,2,5,2,1,4,1]).evaluation_sparse()
-            [(1, 2), (2, 2), (4, 3), (5, 1)]
-            sage: Words("acdb")("abcaccab").evaluation_sparse()
-            [('a', 3), ('c', 3), ('b', 2)]
-        """
-        alphabet_rank = self.alphabet().rank
-        sort_fcn = lambda a,b: cmp(alphabet_rank(a[0]), alphabet_rank(b[0]))
-        return sorted(self.evaluation_dict().items(), sort_fcn)
-
-    def evaluation_partition(self):
-        """
-        Returns the evaluation of the word w as a partition.
-        
-        EXAMPLES::
-        
-            sage: Word("acdabda").evaluation_partition()
-            [3, 2, 1, 1]
-            sage: Word([2,1,4,2,3,4,2]).evaluation_partition()
-            [3, 2, 1, 1]
-        """
-        p = sorted(self.evaluation(), reverse=True)
-        if 0 in p:
-            return Partition(p[:p.index(0)])
-        else:
-            return Partition(p)
-
-    def inversions(self):
-        r"""
-        Returns a list of the inversions of self. An inversion is a pair
-        (i,j) of non-negative integers i j such that self[i] self[j].
-        
-        EXAMPLES::
-        
-            sage: Words([1,2,3])([1,2,3,2,2,1]).inversions()
-            [[1, 5], [2, 3], [2, 4], [2, 5], [3, 5], [4, 5]]
-            sage: Words([3,2,1])([1,2,3,2,2,1]).inversions()
-            [[0, 1], [0, 2], [0, 3], [0, 4], [1, 2]]
-            sage: Words('ab')('abbaba').inversions()
-            [[1, 3], [1, 5], [2, 3], [2, 5], [4, 5]]
-            sage: Words('ba')('abbaba').inversions()
-            [[0, 1], [0, 2], [0, 4], [3, 4]]
-        """
-        return Permutation(list(self._word_content)).inversions()
-
+    # TODO: requires a parent with a cmp_letters method
     def standard_permutation(self):
         r"""
-        Returns the standard permutation of the word self on the ordered
-        alphabet. It is defined as the permutation with exactly the same
-        number of inversions as w. Equivalently, it is the permutation of
-        minimal length whose inverse sorts self.
-        
-        EXAMPLES::
-        
+        Returns the standard permutation of the word
+        self on the ordered alphabet. It is defined as
+        the permutation with exactly the same number of
+        inversions as w. Equivalently, it is the permutation
+        of minimal length whose inverse sorts self.
+
+        EXAMPLES::
+
             sage: w = Word([1,2,3,2,2,1]); w
             word: 123221
             sage: p = w.standard_permutation(); p
             [1, 3, 6, 4, 5, 2]
             sage: v = Word(p.inverse().action(w)); v
             word: 112223
-            sage: Permutations(len(w)).filter( \
+            sage: Permutations(w.length()).filter( \
             ...     lambda q: q.length() <= p.length() and \
             ...               q.inverse().action(w) == list(v) ).list()
             [[1, 3, 6, 4, 5, 2]]
-        
-        ::
-        
+
+        ::
+
             sage: w = Words([1,2,3])([1,2,3,2,2,1,2,1]); w
             word: 12322121
             sage: p = w.standard_permutation(); p
             [1, 4, 8, 5, 6, 2, 7, 3]
             sage: Word(p.inverse().action(w))
             word: 11122223
-        
-        ::
-        
+
+        ::
+
             sage: w = Words([3,2,1])([1,2,3,2,2,1,2,1]); w
             word: 12322121
             sage: p = w.standard_permutation(); p
             [6, 2, 1, 3, 4, 7, 5, 8]
             sage: Word(p.inverse().action(w))
             word: 32222111
-        
-        ::
-        
+
+        ::
+
             sage: w = Words('ab')('abbaba'); w
             word: abbaba
             sage: p = w.standard_permutation(); p
             [1, 4, 5, 2, 6, 3]
             sage: Word(p.inverse().action(w))
             word: aaabbb
-        
-        ::
-        
+
+        ::
+
             sage: w = Words('ba')('abbaba'); w
             word: abbaba
             sage: p = w.standard_permutation(); p
@@ -4415,23 +4399,24 @@
             sage: Word(p.inverse().action(w))
             word: bbbaaa
         """
-        ev = self.evaluation()
+        ev_dict = self.evaluation_dict()
+        ordered_alphabet = sorted(ev_dict, cmp=self.parent().cmp_letters)
         offset = 0
         temp = 0
-        for k in range(len(ev)):
-            temp = ev[k]
-            ev[k] = offset
+        for k in ordered_alphabet:
+            temp = ev_dict[k]
+            ev_dict[k] = offset
             offset += temp
         result = []
-        for l in self._word_content:
-            ev[l] += 1
-            result.append(ev[l])
+        for l in self:
+            ev_dict[l] += 1
+            result.append(ev_dict[l])
         return Permutation(result)
 
     def charge(self, check=True):
-        """
-        EXAMPLES::
-        
+        r"""
+        EXAMPLES::
+
             sage: Word([1,1,2,2,3]).charge()
             0
             sage: Word([3,1,1,2,2]).charge()
@@ -4446,19 +4431,22 @@
             3
             sage: Word([3,2,2,1,1]).charge()
             4
-        
-        TESTS::
-        
+
+        TESTS::
+
             sage: Word([3,3,2,1,1]).charge()
             Traceback (most recent call last):
             ...
             ValueError: the evaluation of the word must be a partition
         """
         if check:
-            if self.evaluation() not in Partitions():
+            ev_dict = self.evaluation_dict()
+            ordered_alphabet = sorted(ev_dict, cmp=self.parent().cmp_letters)
+            evaluation = [ev_dict[a] for a in ordered_alphabet]
+            if evaluation not in Partitions():
                 raise ValueError, "the evaluation of the word must be a partition"
-        w = list(self._word_content)
         res = 0
+        w = self.to_integer_list()
         while len(w) != 0:
             i = 0
             l = min(w)
@@ -4477,33 +4465,283 @@
                     index += 1
         return res
 
+    def BWT(self):
+        r"""
+        Returns the Burrows-Wheeler Transform (BWT) of self.
+        
+        The *Burrows-Wheeler transform* of a finite word `w` is obtained 
+        from `w` by first listing the conjugates of `w` in lexicographic order
+        and then concatenating the final letters of the conjugates in this
+        order. See [1].
+            
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('abaccaaba').BWT()
+            word: cbaabaaca
+            sage: W('abaab').BWT()
+            word: bbaaa
+            sage: W('bbabbaca').BWT()
+            word: cbbbbaaa
+            sage: W('aabaab').BWT()
+            word: bbaaaa
+            sage: Word().BWT()
+            word: 
+            sage: W('a').BWT()
+            word: a
+            
+        REFERENCES:
+
+        -   [1] M. Burrows, D.J. Wheeler, "A block-sorting lossless data
+            compression algorithm", HP Lab Technical Report, 1994, available
+            at http://www.hpl.hp.com/techreports/Compaq-DEC/SRC-RR-124.html
+        """
+        if self.is_empty():
+           return self
+        conjugates = self._conjugates_list()
+        conjugates.sort()
+        return self.parent()([x[x.length()-1] for x in conjugates])
+
+    ###########################################################################
+    ##### DEPRECATION WARNINGS ################################################
+    ##### Added July 2009 #####################################################
+    ###########################################################################
+    def iterated_palindromic_closure(self, side='right', f=None):
+        r"""
+        Returns the iterated (`f`-)palindromic closure of self.
+                            
+        INPUT:
+
+        -  ``side`` - 'right' or 'left' (default: 'right') the direction of the 
+           closure
+        -  ``f`` - involution (default: None) on the alphabet of self. It must 
+           be callable on letters as well as words (e.g. WordMorphism).
+                             
+        OUTPUT:
+
+            word -- If f is None, the right iterated palindromic closure of
+            self; otherwise, the right iterated f-palindromic closure
+            of self.  If side is 'left', the left palindromic closure.
+                    
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('123').iterated_palindromic_closure()
+            doctest:1: DeprecationWarning: iterated_palindromic_closure is deprecated, use iterated_left_palindromic_closure or iterated_right_palindromic_closure instead!
+            word: 1213121
+            sage: W('123').iterated_palindromic_closure(side='left')
+            word: 3231323
+            sage: W('1').iterated_palindromic_closure()
+            word: 1
+            sage: W().iterated_palindromic_closure()
+            word: 
+            sage: W = Words('ab')
+            sage: f = WordMorphism('a->b,b->a')
+            sage: W('ab').iterated_palindromic_closure(f=f)            
+            word: abbaab
+            sage: W('ab').iterated_palindromic_closure(f=f, side='left')
+            word: abbaab
+            sage: W('aab').iterated_palindromic_closure(f=f)            
+            word: ababbaabab
+            sage: W('aab').iterated_palindromic_closure(f=f, side='left')
+            word: abbaabbaab
+            
+        TESTS::
+
+            sage: W('aab').iterated_palindromic_closure(f=f, side='leftt')
+            Traceback (most recent call last):
+            ...
+            ValueError: side must be either 'left' or 'right' (not leftt) 
+
+        If f is not an involution:
+            sage: f = WordMorphism('a->b,b->b')
+            sage: W('aab').iterated_palindromic_closure(f=f, side='left') 
+            Traceback (most recent call last):
+            ...
+            ValueError: f must be an involution
+            
+        REFERENCES:
+
+        -   A. de Luca, A. De Luca, Pseudopalindrome closure operators
+            in free monoids, Theoret. Comput. Sci. 362 (2006) 282--300.      
+        """
+        from sage.misc.misc import deprecation
+        deprecation("iterated_palindromic_closure is deprecated, "
+                   +"use iterated_left_palindromic_closure or "
+                   +"iterated_right_palindromic_closure instead!")
+
+        if side == 'right':
+            return self.iterated_right_palindromic_closure(f=f)
+        elif side == 'left':
+            return self.iterated_left_palindromic_closure(f=f)
+        else:
+            raise ValueError, "side must be either 'left' or 'right' (not %s) " % side
+
+    def iterated_left_palindromic_closure(self, f=None):
+        r"""
+        Returns the iterated left (`f`-)palindromic closure of self.
+                            
+        INPUT:
+
+        -  ``f`` - involution (default: None) on the alphabet of self. It must 
+           be callable on letters as well as words (e.g. WordMorphism).
+                             
+        OUTPUT:
+
+            word -- the left iterated f-palindromic closure of self.
+                    
+        EXAMPLES::
+
+            sage: W = Word
+            sage: W('123').iterated_left_palindromic_closure()
+            word: 3231323
+            sage: f = WordMorphism('a->b,b->a')
+            sage: W('ab').iterated_left_palindromic_closure(f=f)
+            word: abbaab
+            sage: W('aab').iterated_left_palindromic_closure(f=f)
+            word: abbaabbaab
+            
+        TESTS:
+
+        If f is not a involution::
+
+            sage: f = WordMorphism('a->b,b->b')
+            sage: W('aab').iterated_left_palindromic_closure(f=f) 
+            Traceback (most recent call last):
+            ...
+            ValueError: f must be an involution
+            
+        REFERENCES:
+
+        -   A. de Luca, A. De Luca, Pseudopalindrome closure operators
+            in free monoids, Theoret. Comput. Sci. 362 (2006) 282--300.      
+        """
+        if f is None:
+            return self.reversal().iterated_right_palindromic_closure(f=f)
+        else:
+            from sage.combinat.words.morphism import WordMorphism
+            f = WordMorphism(f)
+            return f(self).reversal().iterated_right_palindromic_closure(f=f)
+
+    def count(self, letter):
+        r"""
+        Counts the number of occurrences of letter in self.
+        
+        EXAMPLES::
+
+            sage: Word('abbabaab').count('a')
+            4
+        """
+        return Integer(sum(1 for a in self if a == letter))
+
+    def is_balanced(self, q=1):
+        r"""
+        Returns True if self is `q`-balanced, and False otherwise.
+        
+        A finite or infinite word `w` is said to be *`q`-balanced* if for
+        any two factors `u`, `v` of `w` of the same length, the difference
+        between the number of `x`'s in each of `u` and `v` is at most `q`
+        for all letters `x` in the alphabet of `w`. A `1`-balanced word is
+        simply said to be balanced. See for instance [1] and Chapter 2 of
+        [2].
+            
+        INPUT:
+
+        -  ``q`` - integer (default 1), the balance level
+        
+        OUTPUT:
+
+            boolean -- the result
+            
+        EXAMPLES::
+
+            sage: Word('1213121').is_balanced()
+            True
+            sage: Word('1122').is_balanced()
+            False
+            sage: Word('121333121').is_balanced()
+            False
+            sage: Word('121333121').is_balanced(2)
+            False
+            sage: Word('121333121').is_balanced(3)
+            True
+            sage: Word('121122121').is_balanced()
+            False
+            sage: Word('121122121').is_balanced(2)
+            True
+
+        TESTS::
+
+            sage: Word('121122121').is_balanced(-1)
+            Traceback (most recent call last):
+            ...
+            TypeError: the balance level must be a positive integer
+            sage: Word('121122121').is_balanced(0)
+            Traceback (most recent call last):
+            ...
+            TypeError: the balance level must be a positive integer
+            sage: Word('121122121').is_balanced('a')
+            Traceback (most recent call last):
+            ...
+            TypeError: the balance level must be a positive integer
+            
+        REFERENCES:
+
+        -   [1] J. Cassaigne, S. Ferenczi, L.Q. Zamboni, Imbalances in
+            Arnoux-Rauzy sequences, Ann. Inst. Fourier (Grenoble) 50 (2000)
+            1265--1276.
+        -   [2] M. Lothaire, Algebraic Combinatorics On Words, vol. 90 of
+            Encyclopedia of Mathematics and its Applications, Cambridge
+            University Press, U.K., 2002.
+        """
+        if not isinstance(q, (int, Integer)) or q <= 0:
+            raise TypeError, "the balance level must be a positive integer"
+        alphabet = set(self)
+        for i in xrange(2, self.length()):
+            empty_sets = [set() for _ in range(len(alphabet))]
+            tab = dict(zip(alphabet, empty_sets))
+            for fact in self.factor_iterator(i):
+                evaluation_dict = fact.evaluation_dict() 
+                for a in alphabet:
+                    tab[a].add(evaluation_dict.get(a, 0))
+            for t in tab.values():
+                if len(t) > q+1:
+                    return False
+        return True
+
+    # TODO.
+    # 1. Those three swap functions should use the cmp of python.
+    # 2. The actual code should then be copied as is in the Word_over_Alphabet
+    # and continue to use the parent cmp
+    # 3. Once Word can define Words over alphabet, the examples
+    # should be updated approprietly.
     def swap(self, i, j=None):
-        """
-        Returns the word w with entries at positions i and j swapped. By
-        default, j = i+1.
-        
-        EXAMPLES::
-        
+        r"""
+        Returns the word w with entries at positions i and
+        j swapped. By default, j = i+1.
+        
+        EXAMPLES::
+
             sage: Word([1,2,3]).swap(0,2)
             word: 321
             sage: Word([1,2,3]).swap(1)
             word: 132
-            sage: Words("ba")("abba").swap(1,-1)
+            sage: Word("abba").swap(1,-1)
             word: aabb
         """
         if j == None:
             j = i+1
         new = list(self)
         (new[i], new[j]) = (new[j], new[i])
-        return self.parent()(new)
+        return Word(new)
 
     def swap_increase(self, i):
-        """
-        Returns the word with positions i and i+1 exchanged if self[i] >
-        self[i+1]. Otherwise, it returns self.
-        
-        EXAMPLES::
-        
+        r"""
+        Returns the word with positions i and i+1 exchanged
+        if self[i] > self[i+1]. Otherwise, it returns self.
+
+        EXAMPLES::
+
             sage: w = Word([1,3,2])
             sage: w.swap_increase(1)
             word: 123
@@ -4516,18 +4754,18 @@
             sage: Words("ba")("abba").swap_increase(0)
             word: baba
         """
-        if self.alphabet().rank(self[i]) > self.alphabet().rank(self[i+1]):
+        if self._parent.cmp_letters(self[i], self[i+1]) > 0:
             return self.swap(i)
         else:
             return self
 
     def swap_decrease(self, i):
-        """
-        Returns the word with positions i and i+1 exchanged if self[i] <
-        self[i+1]. Otherwise, it returns self.
-        
-        EXAMPLES::
-        
+        r"""
+        Returns the word with positions i and i+1 exchanged
+        if self[i] < self[i+1]. Otherwise, it returns self.
+
+        EXAMPLES::
+
             sage: w = Word([1,3,2])
             sage: w.swap_decrease(0)
             word: 312
@@ -4540,230 +4778,94 @@
             sage: Words("ba")("abba").swap_decrease(0)
             word: abba
         """
-        if self.alphabet().rank(self[i]) < self.alphabet().rank(self[i+1]):
+        if self._parent.cmp_letters(self[i], self[i+1]) < 0:
             return self.swap(i)
         else:
             return self
 
-    def lex_less(self, other):
-        """
-        Returns True if self is lexicographically less than other.
-        
-        EXAMPLES::
-        
-            sage: w = Word([1,2,3])
-            sage: u = Word([1,3,2])
-            sage: v = Word([3,2,1])
-            sage: w.lex_less(u)
-            True
-            sage: v.lex_less(w)
-            False
-            sage: a = Word("abba")
-            sage: b = Word("abbb")
-            sage: a.lex_less(b)
-            True
-            sage: b.lex_less(a)
-            False
-        """
-        return self < other 
-
-    def lex_greater(self, other):
-        """
-        Returns True if self is lexicographically greater than other.
-        
-        EXAMPLES::
-        
-            sage: w = Word([1,2,3])
-            sage: u = Word([1,3,2])
-            sage: v = Word([3,2,1])
-            sage: w.lex_greater(u)
-            False
-            sage: v.lex_greater(w)
-            True
-            sage: a = Word("abba")
-            sage: b = Word("abbb")
-            sage: a.lex_greater(b)
-            False
-            sage: b.lex_greater(a)
-            True
-        """
-        return self > other 
-
-    def degree(self, weights=None):
-        """
-        Returns the weighted degree of self, where the weighted degree of
-        each letter in the ordered alphabet is given by weights, which
-        defaults to [1, 2, 3, ...].
-        
-        INPUTS: weights - a list or tuple, or a dictionary keyed by the
-        letters occurring in self.
-        
-        EXAMPLES::
-        
-            sage: Word([1,2,3]).degree()
-            6
-            sage: Word([3,2,1]).degree()
-            6
-            sage: Word("abba").degree()
-            6
-            sage: Word("abba").degree([0,2])
-            4
-            sage: Word("abba").degree([-1,-1])
-            -4
-            sage: Word("aabba").degree([1,1])
-            5
-            sage: Words([1,2,4])([1,2,4]).degree()
-            6
-            sage: Words([1,2,3,4])([1,2,4]).degree()
-            7
-            sage: Word("aabba").degree({'a':1,'b':2})
-            7
-            sage: Word([0,1,0]).degree({0:17,1:0})
-            34
-        """
-        deg = 0
-        if weights is None:
-            for a in self._word_content:
-                deg += a+1
-        elif isinstance(weights, (list,tuple)):
-            for a in self._word_content:
-                deg += weights[a]
-        elif isinstance(weights, dict):
-            for a in self:
-                deg += weights[a]
-        else:
-            raise TypeError, "incorrect type for weights"
-        return deg
-
-    def deg_lex_less(self, other, weights=None):
-        """
-        Returns True if self is degree lexicographically less than other,
-        and False otherwise. The weight of each letter in the ordered
-        alphabet is given by weights, which defaults to [1, 2, 3, ...].
-        
-        EXAMPLES::
-        
-            sage: Word([1,2,3]).deg_lex_less(Word([1,3,2]))
-            True
-            sage: Word([3,2,1]).deg_lex_less(Word([1,2,3]))
-            False
-            sage: W = Words(range(5))
-            sage: W([1,2,4]).deg_lex_less(W([1,3,2]))
-            False
-            sage: Word("abba").deg_lex_less(Word("abbb"))
-            True
-            sage: Word("abba").deg_lex_less(Word("baba"))
-            True
-            sage: Word("abba").deg_lex_less(Word("aaba"))
-            False
-            sage: Word("abba").deg_lex_less(Word("aaba"),[1,0])
-            True
-        """
-        deg_self = self.degree(weights)
-        deg_other = other.degree(weights)
-        if deg_self != deg_other:
-            return deg_self < deg_other
-        return self.lex_less(other)
-
-    def inv_lex_less(self, other):
-        """
-        Returns True if self is inverse lexicographically less than other.
-        
-        EXAMPLES::
-        
-            sage: W = Words([1,2,3,4])
-            sage: W([1,2,4]).inv_lex_less(W([1,3,2]))
-            False
-            sage: W([3,2,1]).inv_lex_less(W([1,2,3]))
-            True
-        """
-        if len(self) != len(other):
-            return len(self) < len(other)
-        return self.reversal() < other.reversal()
-
-    def deg_inv_lex_less(self,other,weights=None):
-        """
-        Returns True if the word self is degree inverse lexicographically
-        less than other.
-        
-        EXAMPLES::
-        
-            sage: W = Words([1,2,3,4])
-            sage: W([1,2,4]).deg_inv_lex_less(W([1,3,2]))
-            False
-            sage: W([3,2,1]).deg_inv_lex_less(W([1,2,3]))
-            True
-        """
-        d1 = self.degree(weights)
-        d2 = other.degree(weights)
-        if d1 != d2:
-            return d1 < d2
-        return self.inv_lex_less(other)
-
-    def rev_lex_less(self,other):
-        """
-        Returns True if the word self is reverse lexicographically less
-        than other.
-        
-        EXAMPLES::
-        
-            sage: W = Words([1,2,3,4])
-            sage: W([1,2,4]).rev_lex_less(W([1,3,2]))
-            True
-            sage: W([3,2,1]).rev_lex_less(W([1,2,3]))
-            False
-        """
-        if len(self) != len(other):
-            return len(self) > len(other)
-        return self.reversal() > other.reversal()
-
-    def deg_rev_lex_less(self, other, weights=None):
-        """
-        Returns True if self is degree reverse lexicographically less than
-        other.
-        
-        EXAMPLES::
-        
-            sage: Word([3,2,1]).deg_rev_lex_less(Word([1,2,3]))
-            False
-            sage: W = Words([1,2,3,4])
-            sage: W([1,2,4]).deg_rev_lex_less(W([1,3,2]))
-            False
-            sage: W([1,2,3]).deg_rev_lex_less(W([1,2,4]))
-            True
-        """
-        d1 = self.degree(weights)
-        d2 = other.degree(weights)
-        if d1 != d2:
-            return d1 < d2
-        return self.rev_lex_less(other)
+    def parikh_vector(self, alphabet=None):
+        r"""
+        Returns the Parikh vector of self, i.e., the vector containing the
+        number of occurrences of each letter, given in the order of the
+        alphabet.
+        
+        See also evaluation_dict.
+
+        INPUT: 
+
+        -  ``alphabet`` - (default: None) finite ordered alphabet, if None it 
+           uses the set of letters in self with the ordering defined by the
+           parent
+        
+        EXAMPLES::
+
+            sage: Words('ab')().parikh_vector()
+            [0, 0]
+            sage: Word('aabaa').parikh_vector('abc')
+            [4, 1, 0]
+            sage: Word('a').parikh_vector('abc')
+            [1, 0, 0]
+            sage: Word('a').parikh_vector('cab')
+            [0, 1, 0]
+            sage: Word('a').parikh_vector('bca')
+            [0, 0, 1]
+            sage: Word().parikh_vector('ab')
+            [0, 0]
+            sage: Word().parikh_vector('abc')
+            [0, 0, 0]
+            sage: Word().parikh_vector('abcd')
+            [0, 0, 0, 0]
+
+        TESTS::
+
+            sage: Word('aabaa').parikh_vector()
+            Traceback (most recent call last):
+            ...
+            TypeError: the alphabet is infinite; specify a finite alphabet or use evaluation_dict() instead
+        """
+        if alphabet is None and self._parent.size_of_alphabet() is Infinity:
+            raise TypeError, "the alphabet is infinite; specify a finite alphabet or use evaluation_dict() instead"
+        if alphabet is None:
+            alphabet = self._parent._alphabet
+        ev_dict = self.evaluation_dict()
+        return [ev_dict.get(a,0) for a in alphabet]
+
+    evaluation = parikh_vector
 
     def shuffle(self, other, overlap=0):
-        """
+        r"""
         Returns the combinatorial class representing the shuffle product
         between words self and other. This consists of all words of length
-        len(self)+len(other) that have both self and other as subwords.
-        
+        self.length()+other.length() that have both self and other as 
+        subwords.
+
         If overlap is non-zero, then the combinatorial class representing
         the shuffle product with overlaps is returned. The calculation of
         the shift in each overlap is done relative to the order of the
         alphabet. For example, "a" shifted by "a" is "b" in the alphabet
         [a, b, c] and 0 shifted by 1 in [0, 1, 2, 3] is 2.
-        
-        EXAMPLES::
-        
-            sage: W = Words("abcd")
-            sage: ab = W("ab")
-            sage: cd = W("cd")
+
+        INPUT:
+
+        -  ``other`` - finite word
+        -  ``overlap`` - (default: 0) integer or True
+
+        OUTPUT:
+
+            Combinatorial class of shuffle product of self and other
+
+        EXAMPLES::
+
+            sage: ab = Word("ab")
+            sage: cd = Word("cd")
             sage: sp = ab.shuffle(cd); sp
             Shuffle product of word: ab and word: cd
             sage: sp.cardinality()
             6
             sage: sp.list()
             [word: abcd, word: acbd, word: acdb, word: cabd, word: cadb, word: cdab]
-            sage: W = Words(range(10))
-            sage: w = W([0,1])
-            sage: u = W([2,3])
+            sage: w = Word([0,1])
+            sage: u = Word([2,3])
             sage: w.shuffle(w)
             Shuffle product of word: 01 and word: 01
             sage: u.shuffle(u)
@@ -4773,47 +4875,462 @@
             sage: w.shuffle(u,2)
             Overlapping shuffle product of word: 01 and word: 23 with 2 overlaps
         """
-        if overlap is True:
-            from sage.combinat.words.shuffle_product import ShuffleProduct_overlapping
-            return ShuffleProduct_overlapping(self, other)
-        elif overlap == 0:
+        if overlap == 0:
             from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2
             return ShuffleProduct_w1w2(self, other)
-        elif isinstance(overlap, (int,Integer)):
-            from sage.combinat.words.shuffle_product import ShuffleProduct_overlapping_r
-            return ShuffleProduct_overlapping_r(self, other, overlap)
-        raise ValueError, 'overlapping must be True or an integer'
-
-    def shifted_shuffle(self, other):
-        """
+        else:
+            if any(a not in ZZ for a in self) or any(a not in ZZ for a in other):
+                raise ValueError, "for a nonzero overlap, words must contain integers as letters"
+            if overlap is True:
+                from sage.combinat.words.shuffle_product import ShuffleProduct_overlapping
+                return ShuffleProduct_overlapping(self, other)
+            elif isinstance(overlap, (int,Integer)):
+                from sage.combinat.words.shuffle_product import ShuffleProduct_overlapping_r
+                return ShuffleProduct_overlapping_r(self, other, overlap)
+            raise ValueError, 'overlapping must be True or an integer'
+
+    def shifted_shuffle(self, other, shift=None):
+        r"""
         Returns the combinatorial class representing the shifted shuffle
         product between words self and other. This is the same as the
         shuffle product of self with the word obtained from other by
-        incrementing the values by len(self).
-        
-        EXAMPLES::
-        
-            sage: W = Words("abcd")
-            sage: ab = W("ab")
-            sage: cd = W("cd")
-            sage: sp = ab.shifted_shuffle(ab); sp
-            Shuffle product of word: ab and word: cd
+        incrementing its values (i.e. its letters) by the given shift.
+
+        INPUT:
+
+        -  ``other`` - finite word over the integers
+        -  ``shift`` - integer or None (default: None) added to each letter of 
+           other. When shift is None, it is replaced by self.length()
+
+        OUTPUT:
+
+            Combinatorial class of shifted shuffle products of self and
+            other.
+
+        EXAMPLES::
+
+            sage: w = Word([0,1,1])
+            sage: sp = w.shifted_shuffle(w); sp
+            Shuffle product of word: 011 and word: 344
+            sage: sp = w.shifted_shuffle(w, 2); sp
+            Shuffle product of word: 011 and word: 233 
             sage: sp.cardinality()
-            6
+            20
+            sage: WordOptions(identifier='')
             sage: sp.list()
-            [word: abcd, word: acbd, word: acdb, word: cabd, word: cadb, word: cdab]
-        """
-        # TODO: type checking: what if the alphabet is too small? error?
-        wc = BuildWordContent([x + len(self) for x in other._word_content])
-        return self.shuffle(other.parent()(wc))
+            [011233, 012133, 012313, 012331, 021133, 021313, 021331, 023113, 023131, 023311, 201133, 201313, 201331, 203113, 203131, 203311, 230113, 230131, 230311, 233011]
+            sage: WordOptions(identifier='word: ')
+            sage: y = Word('aba')
+            sage: y.shifted_shuffle(w,2)
+            Traceback (most recent call last):
+            ...
+            ValueError: for shifted shuffle, words must only contain integers as letters
+        """
+        if any(a not in ZZ for a in self) or any(a not in ZZ for a in other):
+            raise ValueError, "for shifted shuffle, words must only contain integers as letters"
+        if shift is None:
+            from sage.combinat.words.shuffle_product import ShuffleProduct_shifted
+            return ShuffleProduct_shifted(self, other)
+        else:
+            return self.shuffle(self._parent([x + shift for x in other]))
+
+    def delta_inv(self, W=None, s=None):
+        r"""
+        Lifts self via the delta operator to obtain a word containing the
+        letters in alphabet (default is [0, 1]). The letters used in the
+        construction start with s (default is alphabet[0]) and cycle
+        through alphabet.
+        
+        INPUT:
+
+        -  ``alphabet`` - an iterable
+        -  ``s`` - an object in the iterable
+
+        EXAMPLES::
+
+            sage: W = Words([1, 2])
+            sage: W([2, 2, 1, 1]).delta_inv()
+            word: 112212
+            sage: W([1, 1, 1, 1]).delta_inv(Words('123'))
+            word: 1231
+            sage: W([2, 2, 1, 1, 2]).delta_inv(s=2)
+            word: 22112122
+        """
+        alphabet = [1, 2] if W is None else W.alphabet()
+        cycle_alphabet = cycle(alphabet)
+        if self.is_empty():
+            return Words(alphabet)()
+        if s is None:
+            s = cycle_alphabet.next()
+        else:
+            if s not in alphabet:
+                raise ValueError, "starting letter not in alphabet"
+            t = cycle_alphabet.next()
+            while t != s:
+                t = cycle_alphabet.next()
+        w = []
+        for i in self:
+            w.extend([s] * i)
+            s = cycle_alphabet.next()
+        return Words(alphabet)(w)
+
+    def delta(self):
+        r"""
+        Returns the image of self under the delta morphism. This is the
+        word composed of the length of consecutive runs of the same letter
+        in a given word.
+        
+        EXAMPLES::
+
+            sage: W = Words('0123456789')
+            sage: W('22112122').delta()
+            word: 22112
+            sage: W('555008').delta()
+            word: 321
+            sage: W().delta()
+            word: 
+            sage: Word('aabbabaa').delta()
+            word: 22112
+
+        """
+        if self.is_empty():
+            return Words()([])
+        ss = self[0]
+        c = 0
+        v = list()
+        max_c = 0
+        for s in self:
+            if s == ss:
+                c += 1
+                if c > max_c:
+                    max_c = c
+            else:
+                v.append(c)
+                ss = s
+                c = 1
+        v.append(c)
+        return Words(range(1,1+max_c))(v)
+
+    # TODO. Decide whether delta_derivate* really need W.alphabet().last()....
+    # RENAME: Should "derivate" be derivative?!
+
+    def delta_derivate(self, W=None):
+        r"""
+        Returns the derivative under delta for self.
+        
+        EXAMPLES::
+        
+            sage: W = Words('12')
+            sage: W('12211').delta_derivate()
+            word: 22
+            sage: W('1').delta_derivate(Words([1]))
+            word: 1
+            sage: W('2112').delta_derivate()
+            word: 2
+            sage: W('2211').delta_derivate()
+            word: 22
+            sage: W('112').delta_derivate()
+            word: 2
+            sage: W('11222').delta_derivate(Words([1, 2, 3]))
+            word: 3
+        """
+        d = self.delta()
+        if len(d) == 0:
+            return d
+        if W is None:
+            W = d.parent()
+        if d[0] != W.alphabet().last():
+            d = d[1:]
+        if d[-1] != W.alphabet().last():
+            d = d[:-1]
+        return d
+
+    def delta_derivate_left(self, W=None):
+        r"""
+        Returns the derivative under delta for self.
+        
+        EXAMPLES::
+        
+            sage: W = Words('12')
+            sage: W('12211').delta_derivate_left()
+            word: 22
+            sage: W('1').delta_derivate_left(Words([1]))
+            word: 1
+            sage: W('2112').delta_derivate_left()
+            word: 21
+            sage: W('2211').delta_derivate_left()
+            word: 22
+            sage: W('112').delta_derivate_left()
+            word: 21
+            sage: W('11222').delta_derivate_left(Words([1, 2, 3]))
+            word: 3
+        """
+        d = self.delta()
+        if len(d) == 0:
+            return d
+        if W is None:
+            W = d.parent()
+        if d[0] != W.alphabet().last():
+            d = d[1:]
+        return d
+
+    def delta_derivate_right(self, W=None):
+        r"""
+        Returns the right derivative under delta for self.
+        
+        EXAMPLES::
+        
+            sage: W = Words('12')
+            sage: W('12211').delta_derivate_right()
+            word: 122
+            sage: W('1').delta_derivate_right(Words([1]))
+            word: 1
+            sage: W('2112').delta_derivate_right()
+            word: 12
+            sage: W('2211').delta_derivate_right()
+            word: 22
+            sage: W('112').delta_derivate_right()
+            word: 2
+            sage: W('11222').delta_derivate_right(Words([1, 2, 3]))
+            word: 23
+        """
+        d = self.delta()
+        if len(d) == 0:
+            return d
+        if W is None:
+            W = d.parent()
+        if d[-1] != W.alphabet().last():
+            d = d[:-1]
+        return d
+
+    def phi(self):
+        r"""
+        Applies the phi function to self and returns the result. This is
+        the word obtained by taking the first letter of the words obtained
+        by iterating delta on self.
+        
+        OUTPUT:
+
+            word -- the result of the phi function
+            
+        EXAMPLES::
+
+            sage: W = Words([1, 2])
+            sage: W([2,2,1,1,2,1,2,2,1,2,2,1,1,2]).phi()
+            word: 222222
+            sage: W([2,1,2,2,1,2,2,1,2,1]).phi()
+            word: 212113
+            sage: W().phi()
+            word: 
+            sage: Word([2,1,2,2,1,2,2,1,2,1]).phi()
+            word: 212113
+            sage: Word([2,3,1,1,2,1,2,3,1,2,2,3,1,2]).phi()
+            word: 21215
+            sage: Word("aabbabaabaabba").phi()
+            word: a22222
+            sage: w = Word([2,3,1,1,2,1,2,3,1,2,2,3,1,2])
+        
+        REFERENCES:
+
+        -   S. Brlek, A. Ladouceur, A note on differentiable palindromes,
+            Theoret. Comput. Sci. 302 (2003) 167--178.
+        -   S. Brlek, S. Dulucq, A. Ladouceur, L. Vuillon, Combinatorial
+            properties of smooth infinite words, Theoret. Comput. Sci. 352
+            (2006) 306--317.
+        """
+        if self.is_empty():
+            return self
+        v = [self[0]]
+        m = self.delta()
+        while m.length() > 1:
+            v.append(m[0])
+            m = m.delta()
+        v.append(m[0])
+        return Words()(v)
+
+    def phi_inv(self, W=None):
+        r"""
+        Apply the inverse of the phi function to self.
+        
+        INPUT:
+
+        -  ``self`` - a word over the integers
+        -  ``W`` - a parent object of words defined over integers
+        
+        OUTPUT:
+
+            word -- the inverse of the phi function
+        
+        EXAMPLES::
+
+            sage: W = Words([1, 2])
+            sage: W([2, 2, 2, 2, 1, 2]).phi_inv()
+            word: 22112122
+            sage: W([2, 2, 2]).phi_inv(Words([2, 3]))
+            word: 2233
+        """
+        if W is None:
+            W = self.parent()
+        if self.is_empty():
+            return W()
+        v = self.parent()((self[-1],))
+        for i in xrange(self.length()-2, -1, -1):
+            v = v.delta_inv(W, self[i])
+        return v
+
+    def _phi_inv_tab(self, tab):
+        r"""
+        Specialized version of phi_inv() for long or incremental words.
+        
+        TESTS::
+
+            sage: Words([1, 2])([1, 1, 2, 2])._phi_inv_tab([2])
+            word: 12211
+        """
+        res = self.delta_inv(s=tab[0])
+        res = res[1:]
+        for i in xrange(1, len(tab)):
+            res = res.delta_inv(s=tab[i])
+        return res
+
+    def is_smooth_prefix(self):
+        r"""
+        Returns True if self is the prefix of a smooth word, and False
+        otherwise.
+        
+        Let `A_k = \{1, \ldots ,k\}`, `k \geq 2`. An infinite word `w` in
+        `A_k^\omega` is said to be *smooth* if and only if for all positive
+        integers `m`, `\Delta^m(w)` is in `A_k^\omega`, where `\Delta(w)` is
+        the word obtained from `w` by composing the length of consecutive
+        runs of the same letter in `w`. See for instance [1] and [2].
+        
+        INPUT:
+
+        -  ``self`` - must be a word over the integers to get something other
+           than False
+        
+        OUTPUT:
+
+            boolean -- whether self is a smooth prefix or not
+        
+        EXAMPLES::
+
+            sage: W = Words([1, 2])
+            sage: W([1, 1, 2, 2, 1, 2, 1, 1]).is_smooth_prefix()
+            True
+            sage: W([1, 2, 1, 2, 1, 2]).is_smooth_prefix()
+            False
+            
+        REFERENCES:
+        
+        -   [1] S. Brlek, A. Ladouceur, A note on differentiable palindromes,
+            Theoret. Comput. Sci. 302 (2003) 167--178.
+        -   [2] S. Brlek, S. Dulucq, A. Ladouceur, L. Vuillon, Combinatorial
+            properties of smooth infinite words, Theoret. Comput. Sci. 352
+            (2006) 306--317.
+        """
+        m = self
+        W = self.parent()
+        while m.length() > 1:
+            m = m.delta_derivate_right()
+            if not all(W.has_letter(a) for a in m.letters()):
+                return False
+        return True
+
+    def letters(self):
+        r"""
+        Return a list of the letters that appear in self, listed in the
+        order of first appearance.
+
+        EXAMPLES::
+
+            sage: Word([0,1,1,0,1,0,0,1]).letters()
+            [0, 1]
+            sage: Word("cacao").letters()
+            ['c', 'a', 'o']
+        """
+        seen, res = {}, []
+        for x in self:
+            if not seen.has_key(x):
+                res.append(x)
+                seen[x] = True
+        return res
+
+    def standard_factorization(self):
+        r"""
+        Returns the standard factorization of self.
+        
+        The *standard factorization* of a word `w` is the unique
+        factorization: `w = uv` where `v` is the longest proper suffix
+        of `w` that qualifies as a Lyndon word.
+        
+        Note that if `w` is a Lyndon word with standard factorization
+        `w = uv`, then `u` and `v` are also Lyndon words and `u < v`.
+            
+        See for instance [1] and [2].
+        
+        OUTPUT:
+
+            list -- the list of factors
+        
+        EXAMPLES::
+
+            sage: Words('01')('0010110011').standard_factorization()
+            (001011.0011)
+            sage: Words('123')('1223312').standard_factorization()
+            (12233.12)
+
+        ::
+
+            sage: w = Word('0010110011',alphabet='01')
+            sage: w.standard_factorization()
+            (001011.0011)
+            sage: w = Word('0010110011',alphabet='10')
+            sage: w.standard_factorization()
+            (0010110011.)
+            sage: w = Word('1223312',alphabet='123')
+            sage: w.standard_factorization()
+            (12233.12)
+            
+        REFERENCES:
+
+        -   [1] K.-T. Chen, R.H. Fox, R.C. Lyndon, Free differential calculus,
+            IV. The quotient groups of the lower central series, Ann. of Math.
+            68 (1958) 81--95.
+        -   [2] J.-P. Duval, Factorizing words over an ordered alphabet,
+            J. Algorithms 4 (1983) 363--381.
+        """
+        suff = self[1:]
+        for l in xrange(1, self.length()):
+            pref = self[:l]
+            if pref.is_lyndon() and suff.is_lyndon():
+                return Factorization([pref, suff])
+            suff = suff[1:]
+        return Factorization([self, self.parent()()])
+
+    def standard_factorization_of_lyndon_factorization(self):
+        r"""
+        Returns the standard factorization of the Lyndon factorization
+        of self.
+        
+        OUTPUT:
+
+            list of lists -- the factorization
+        
+        EXAMPLES::
+
+            sage: Words('123')('1221131122').standard_factorization_of_lyndon_factorization()
+            [(12.2), (1.13), (1.122)]
+        """
+        return [x.standard_factorization() for x in self.lyndon_factorization()]
 
     def apply_permutation_to_positions(self, permutation):
         r"""
         Return the word obtained by permuting the positions of the letters
         in self.
-        
-        EXAMPLES::
-        
+
+        EXAMPLES::
+
             sage: w = Words('abcd')('abcd')
             sage: w.apply_permutation_to_positions([2,1,4,3])
             word: badc
@@ -4824,6 +5341,8 @@
             word: badc
             sage: w.apply_permutation_to_positions(PermutationGroupElement([2,1,4,3]))
             word: badc
+            sage: Word([1,2,3,4]).apply_permutation_to_positions([3,4,2,1])
+            word: 3421
         """
         if not isinstance(permutation, Permutation_class):
             if isinstance(permutation, PermutationGroupElement):
@@ -4834,11 +5353,11 @@
 
     def apply_permutation_to_letters(self, permutation):
         r"""
-        Return the word obtained by applying permutation to the letters of
-        the alphabet of self.
-        
-        EXAMPLES::
-        
+        Return the word obtained by applying permutation to 
+        the letters of the alphabet of self.
+
+        EXAMPLES::
+
             sage: w = Words('abcd')('abcd')
             sage: p = [2,1,4,3]
             sage: w.apply_permutation_to_letters(p)
@@ -4849,13 +5368,515 @@
             sage: w.apply_permutation_to_letters(Permutation(p))
             word: badc 
             sage: w.apply_permutation_to_letters(PermutationGroupElement(p))
-            word: badc
+            word: badc 
         """
         if not isinstance(permutation, Permutation_class):
             if isinstance(permutation, PermutationGroupElement):
                 permutation = Permutation(permutation.list())
             else:
                 permutation = Permutation(permutation)
-        alphabet = self.alphabet().list()
+        alphabet = self.parent().alphabet()
         morphism = dict(zip(alphabet, permutation.action(alphabet)))
         return self.apply_morphism(morphism)
+
+    def colored_vector(self, x=0, y=0, width='default', height=1, cmap='hsv', thickness=1, label=None):
+        r"""
+        Returns a vector (Graphics object) illustrating self. Each letter
+        is represented by a coloured rectangle. 
+        
+        If the parent of self is a class of words over a finite alphabet,
+        then each letter in the alphabet is assigned a unique colour, and
+        this colour will be the same every time this method is called. This
+        is especially useful when plotting and comparing words defined on
+        the same alphabet.
+
+        If the alphabet is infinite, then the letters appearing in the word
+        are used as the alphabet.
+
+        INPUT:
+
+        -  ``x`` - (default: 0) bottom left x-coordinate of the vector
+        -  ``y`` - (default: 0) bottom left y-coordinate of the vector
+        -  ``width``  - (default: 'default') width of the vector. By default,
+           the width is the length of self.
+        -  ``height`` - (default: 1) height of the vector
+        -  ``thickness`` - (default: 1) thickness of the contour
+        -  ``cmap`` - (default: 'hsv') color map; for available color map names
+            type: ``import matplotlib.cm; matplotlib.cm.datad.keys()``
+        -  ``label`` - str (default: None) a label to add on the colored vector.
+                 
+        OUTPUT:
+
+            Graphics
+         
+        EXAMPLES::
+
+            sage: Word(range(20)).colored_vector()                
+            sage: Word(range(100)).colored_vector(0,0,10,1)
+            sage: Words(range(100))(range(10)).colored_vector()
+            sage: w = Word('abbabaab')
+            sage: w.colored_vector()
+            sage: w.colored_vector(cmap='autumn')
+            sage: Word(range(20)).colored_vector(label='Rainbow') 
+
+        When two words are defined under the same parent, same letters are
+        mapped to same colors::
+
+            sage: W = Words(range(20))
+            sage: w = W(range(20))
+            sage: y = W(range(10,20))
+            sage: y.colored_vector(y=1, x=10) + w.colored_vector()
+
+        TESTS:
+
+        The empty word::
+
+            sage: Word().colored_vector()
+            sage: Word().colored_vector(label='empty')
+
+        Unknown cmap::
+
+            sage: Word(range(100)).colored_vector(cmap='jolies')
+            Traceback (most recent call last):
+            ...
+            RuntimeError: Color map jolies not known
+            sage: Word(range(100)).colored_vector(cmap='__doc__')
+            Traceback (most recent call last):
+            ...
+            RuntimeError: Color map __doc__ not known
+        """
+        #Recognize the color map
+        import matplotlib.cm as cm
+        from matplotlib.colors import LinearSegmentedColormap as C
+        key_error = False
+        try:
+            mpl_cmap = cm.__dict__[cmap]
+        except KeyError:
+            key_error = True
+
+        if key_error or not isinstance(mpl_cmap, C):
+            possibilities = ', '.join([str(x) for x in cm.__dict__.keys() if \
+                                       isinstance(cm.__dict__[x], C)])
+            import sage.misc.misc
+            sage.misc.misc.verbose("The possible color maps include: %s"%possibilities, level=0)
+            raise RuntimeError, "Color map %s not known"%cmap
+
+        #Drawing the colored vector...
+        from sage.plot.plot import polygon,line,text
+
+        #The default width of the vector
+        if width == 'default':
+            width = self.length()
+
+        #The black frame of the vector
+        ymax = y + height
+        L = [(x,y), (x+width,y), (x+width,ymax), (x,ymax), (x,y)]
+        rep = line(L, rgbcolor=(0,0,0), thickness=thickness)
+
+        #The label
+        if not label is None:
+            hl = height/2.0 # height of the label rectangle
+            ymax2 = ymax + hl
+            rep += text(str(label), (x+width/2.0, ymax + hl/2.0), rgbcolor=(1,0,0))
+            L = [(x,ymax), (x+width,ymax), (x+width,ymax2), (x,ymax2), (x,ymax)]
+            rep += line(L, rgbcolor=(0,0,0), thickness=thickness)
+
+        #base : the width of each rectangle 
+        base = width / float(self.length()) if not self.is_empty() else None
+
+        #A colored rectangle for each letter
+        dim = self.parent().size_of_alphabet()
+        if dim is Infinity:
+            ordered_alphabet = sorted(self.letters(), \
+                    cmp=self.parent().cmp_letters)
+            dim = float(len(ordered_alphabet))
+        else:
+            ordered_alphabet = self.parent().alphabet()
+            dim = float(self.parent().size_of_alphabet())
+        letter_to_integer_dict = dict((a,i) for (i,a) in
+                enumerate(ordered_alphabet))
+        xp = x
+        for a in self:
+            i = letter_to_integer_dict[a]
+            xq = xp + base
+            L = [(xp,y), (xq,y), (xq,ymax), (xp,ymax) ]
+            rgbcolor = mpl_cmap( i / dim ) [:3]
+            rep += polygon(L, rgbcolor = rgbcolor)
+            xp = xq
+        rep.axes(False)
+        return rep
+
+    def is_square(self):
+        r"""
+        Returns True if self is a square, and False otherwise.
+        
+        EXAMPLES::
+        
+            sage: Word([1,0,0,1]).is_square()
+            False
+            sage: W = Words('123')
+            sage: W('1212').is_square()
+            True
+            sage: W('1213').is_square()
+            False
+            sage: W('12123').is_square()
+            False
+            sage: W().is_square()
+            True
+        """
+        if self.length() % 2 != 0:
+            return False
+        else:
+            l = self.length() / 2
+            return self[:l] == self[l:]
+
+    def is_square_free(self):
+        r"""
+        Returns True if self does not contain squares, and False
+        otherwise.
+        
+        EXAMPLES::
+        
+            sage: W = Words('123')
+            sage: W('12312').is_square_free()
+            True
+            sage: W('31212').is_square_free()
+            False
+            sage: W().is_square_free()
+            True
+        """
+        l = self.length()
+        if l < 2:
+            return True
+        suff = self
+        for i in xrange(0, l - 2):
+            for ll in xrange(2, l-i+1, 2):
+                if suff[:ll].is_square():
+                    return False
+            suff = suff[1:]
+        return True
+
+    def is_cube(self):
+        r"""
+        Returns True if self is a cube, and False otherwise.
+        
+        EXAMPLES::
+        
+            sage: W = Words('012')
+            sage: W('012012012').is_cube()
+            True
+            sage: W('01010101').is_cube()
+            False
+            sage: W().is_cube()
+            True
+            sage: W('012012').is_cube()
+            False
+        """
+        if self.length() % 3 != 0:
+            return False
+        l = self.length() / 3
+        return self[:l] == self[l:2*l] == self[2*l:]
+
+    def is_cube_free(self):
+        r"""
+        Returns True if self does not contain cubes, and False otherwise.
+        
+        EXAMPLES::
+        
+            sage: W = Words('123')
+            sage: W('12312').is_cube_free()
+            True
+            sage: W('32221').is_cube_free()
+            False
+            sage: W().is_cube_free()
+            True
+        """
+        l = self.length()
+        if l < 3: 
+            return True
+        suff = self
+        for i in xrange(0, l - 3):
+            for ll in xrange(3, l-i+1, 3):
+                if suff[:ll].is_cube():
+                    return False
+            suff = suff[1:]
+        return True
+
+class InfiniteWord_class(Word_class):
+    def length(self):
+        r"""
+        Returns the length of self.
+
+        EXAMPLES::
+
+            sage: f = lambda n : n % 6
+            sage: w = Word(f); w
+            word: 0123450123450123450123450123450123450123...
+            sage: w.length()
+            +Infinity
+        """
+        return Infinity
+
+#######################################################################
+#                                                                     #
+#                    Concrete word classes                            #
+#                                                                     #
+#######################################################################
+
+##### Finite Words #####
+
+class FiniteWord_list(WordDatatype_list, FiniteWord_class):
+    r"""
+    TESTS::
+
+        sage: w = Word([0,1,1,0])
+        sage: w == loads(dumps(w))
+        True
+    """
+    pass
+
+class FiniteWord_str(WordDatatype_str, FiniteWord_class):
+    r"""
+    TESTS::
+
+        sage: w = Word('abba')
+        sage: w == loads(dumps(w))
+        True
+    """
+    pass
+
+class FiniteWord_tuple(WordDatatype_tuple, FiniteWord_class):
+    r"""
+    TESTS::
+
+        sage: w = Word((0,1,1,0))
+        sage: w == loads(dumps(w))
+        True
+    """
+    pass
+
+class FiniteWord_iter_with_caching(WordDatatype_iter_with_caching, FiniteWord_class):
+    pass
+
+class FiniteWord_iter(WordDatatype_iter, FiniteWord_class):
+    pass
+
+class FiniteWord_callable_with_caching(WordDatatype_callable_with_caching, FiniteWord_class):
+    pass
+
+class FiniteWord_callable(WordDatatype_callable, FiniteWord_class):
+    pass
+
+##### Infinite Words #####
+
+class InfiniteWord_iter_with_caching(WordDatatype_iter_with_caching, InfiniteWord_class):
+    pass
+
+class InfiniteWord_iter(WordDatatype_iter, InfiniteWord_class):
+    pass
+
+class InfiniteWord_callable_with_caching(WordDatatype_callable_with_caching, InfiniteWord_class):
+    pass
+
+class InfiniteWord_callable(WordDatatype_callable, InfiniteWord_class):
+    pass
+
+##### Words of unknown length #####
+
+class Word_iter_with_caching(WordDatatype_iter_with_caching, Word_class):
+    pass
+
+class Word_iter(WordDatatype_iter, Word_class):
+    pass
+
+#######################################################################
+
+class Factorization(list):
+    r"""
+    A list subclass having a nicer representation for factorization of words.
+    
+    TESTS::
+
+        sage: f = sage.combinat.words.word.Factorization()
+        sage: f == loads(dumps(f))
+        True
+    """
+    def __repr__(self):
+        r"""
+        Returns a string representation of the object.
+        
+        TESTS::
+
+            sage: sage.combinat.words.word.Factorization()
+            ()
+            sage: sage.combinat.words.word.Factorization([Word('ab'), Word('ba')])
+            (ab.ba)
+        """
+        return '(%s)' % '.'.join(w.string_rep() for w in self)
+
+class CallableFromListOfWords(tuple):
+    r"""
+    A class to create a callable from a list of words. The concatenation of
+    a list of words is obtained by creating a word from this callable.
+    """
+    def __new__(cls, words):
+        r"""
+        TESTS::
+
+            sage: from sage.combinat.words.word import CallableFromListOfWords
+            sage: w,u,x = Word([1,2,3]),Word([4,5]),Word([6,7,8])
+            sage: f = CallableFromListOfWords([w,u,x]); f
+            (word: 123, word: 45, word: 678)
+            sage: f == loads(dumps(f))
+            True
+        """
+        l = []
+        for w in words:
+            if isinstance(w, WordDatatype_callable) and \
+                    isinstance(w._func, CallableFromListOfWords):
+                l.extend(w._func)
+            else:
+                l.append(w)
+        return tuple.__new__(cls, l)
+
+    def __call__(self, i):
+        r"""
+        Returns the character at position i.
+
+        TESTS::
+
+            sage: from sage.combinat.words.word import CallableFromListOfWords
+            sage: w,u,x = Word([1,2,3]),Word([4,5]),Word([6,7,8])
+            sage: f = CallableFromListOfWords([w,u,x])
+            sage: [f(i) for i in range(8)]
+            [1, 2, 3, 4, 5, 6, 7, 8]
+        """
+        j = i
+        for c in self:
+            if (j - c.length() < 0):
+                return c[j]
+            j -= c.length()
+        raise IndexError, "index (=%s) out of range" % i
+
+#######################################################################
+#                                                                     #
+#                    Old word classes                                 #
+#                                                                     #
+#######################################################################
+
+def _word_from_word_content(data, parent):
+    r"""
+    Create a word with the given parent from a :class:`WordContent` object.
+
+    .. note::
+
+       :class:`WordContent` is deprecated and will be deleted in a future
+       version of Sage. This function exists to maintain backwards
+       compatibility for unpickling objects saved with older versions of Sage.
+
+    TESTS::
+
+        sage: from sage.combinat.words.word import _word_from_word_content
+        sage: import sage.combinat.words.word_content as word_content
+        sage: cl = word_content.WordContentFromList([0, 1, 1, 2, 1])
+        doctest:...: DeprecationWarning: WordContentFromList is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
+        sage: _word_from_word_content(cl,Words([0,1,2]))
+        word: 01121
+        sage: _word_from_word_content(cl,Words([2,1,0]))
+        word: 21101
+
+    ::
+
+        sage: cf = word_content.WordContentFromFunction(lambda x : x)[:10]
+        doctest:...: DeprecationWarning: WordContentFromFunction is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
+        doctest:...: DeprecationWarning: WordContentFromFunction is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
+        sage: _word_from_word_content(cf, Words())
+        word: 0123456789
+
+    ::
+
+        sage: from itertools import count
+        sage: ci = word_content.WordContentFromIterator(count(3))[:5]
+        doctest:...: DeprecationWarning: WordContentFromIterator is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
+        doctest:...: DeprecationWarning: WordContentFromIterator is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
+        sage: _word_from_word_content(ci, Words())
+        word: 34567
+
+    ::
+
+        sage: cc = word_content.ConcatenateContent((cl, cf, ci))
+        doctest:...: DeprecationWarning: ConcatenateContent is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
+        doctest:...: DeprecationWarning: ConcatenateContent is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
+        sage: _word_from_word_content(cc, Words())
+        word: 01121012345678934567
+
+    """
+    from sage.combinat.words import word_content
+    # extract data from WordContent object
+    length = None
+    if isinstance(data, word_content.WordContentFromList):
+        unranker = parent.alphabet().unrank
+        data = map(unranker, data._list)
+        datatype = 'list'
+    elif isinstance(data, word_content.WordContentFromIterator):
+        data = data._get_it()
+        datatype = 'iter'
+    elif isinstance(data, word_content.WordContentFromFunction):
+        length = data._len
+        data = data._func
+        datatype = 'callable'
+    elif isinstance(data, word_content.ConcatenateContent):
+        l = map(_word_from_word_content, data)
+        data = CallableFromListOfWords(l)
+        datatype = 'callable'
+    else:
+        raise TypeError, 'data is not an instance of WordContent'
+    return Word(data=data, alphabet=parent, datatype=datatype, length=length)
+
+class DeprecatedWordClass(SageObject):
+    def __setstate__(self, data):
+        from sage.misc.misc import deprecation
+        cls = self.__class__
+        deprecation('Your word object is saved in an old file format '
+            'since %s is deprecated and will be deleted in a future version '
+            'of Sage (you can use %s instead). You can re-save your word by '
+            'typing "word.save(filename)" to ensure that it will load in '
+            'future versions of Sage.''' %
+            (cls.__name__, cls.__bases__[1].__name__))
+        parent = data['_parent']
+        del data['_parent']
+        wordcontent = data.get('_word_content', None)
+        del data['_word_content']
+        w = _word_from_word_content(wordcontent, parent)
+        self.__class__ = type(w)
+        self.__init__(parent, list(w))
+        for key, item in data.iteritems():
+            setattr(self, key, item)
+
+class AbstractWord(DeprecatedWordClass, FiniteWord_list):
+    pass
+
+class AbstractFiniteWord(DeprecatedWordClass, FiniteWord_list):
+    pass
+
+class AbstractInfiniteWord(DeprecatedWordClass, InfiniteWord_class):
+    pass
+
+class Word_over_Alphabet(DeprecatedWordClass, FiniteWord_list):
+    pass
+
+class Word_over_OrderedAlphabet(DeprecatedWordClass, FiniteWord_list):
+    pass
+
+class FiniteWord_over_Alphabet(DeprecatedWordClass, FiniteWord_list):
+    pass
+
+class FiniteWord_over_OrderedAlphabet(DeprecatedWordClass, FiniteWord_list):
+    pass
+
+class InfiniteWord_over_Alphabet(DeprecatedWordClass, InfiniteWord_class):
+    pass
+
+class InfiniteWord_over_OrderedAlphabet(DeprecatedWordClass, InfiniteWord_class):
+    pass
+
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/words/word_content.py
--- a/sage/combinat/words/word_content.py	Thu Jul 09 15:14:36 2009 -0700
+++ b/sage/combinat/words/word_content.py	Fri Jul 17 23:25:52 2009 +0200
@@ -1,6 +1,14 @@
 # coding=utf-8
 """
-Word contents
+Word contents (DEPRECATED) 
+
+.. note::
+
+    This module will be deleted in a future version of Sage. Most of the
+    commands here have been already deleted; only the commands needed for
+    unpickling word objects saved with older versions of Sage (pre 4.1) have
+    been kept (for now).
+
 """
 #*****************************************************************************
 #       Copyright (C) 2008 Arnaud Bergeron <abergeron@gmail.com>,
@@ -49,6 +57,8 @@
         sage: from sage.combinat.words.word_content import BuildWordContent
         sage: from itertools import count, imap, repeat
         sage: len(BuildWordContent(None))
+        doctest:...: DeprecationWarning: WordContentFromList is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
+        doctest:...: DeprecationWarning: WordContentFromList is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
         0
         sage: len(BuildWordContent(None, format='empty'))
         0
@@ -57,6 +67,7 @@
         ...
         TypeError: trying to build an empty word with something other than None
         sage: len(BuildWordContent(['0', '1', '1'], int))
+        doctest:...: DeprecationWarning: WordContentFromList is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
         3
         sage: len(BuildWordContent(['0', '1', '1'], int, format='list'))
         3
@@ -65,12 +76,17 @@
         ...
         TypeError: trying to build a word backed by a list with a sequence not providing the required operations
         sage: c = BuildWordContent(lambda x: x%2)
+        doctest:...: DeprecationWarning: WordContentFromFunction is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
+        doctest:...: DeprecationWarning: WordContentFromFunction is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
         sage: len(BuildWordContent(lambda x: x%3, part=slice(0,10)))
         10
         sage: c = BuildWordContent(repeat(1))
+        doctest:...: DeprecationWarning: WordContentFromIterator is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
+        doctest:...: DeprecationWarning: WordContentFromIterator is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
         sage: len(BuildWordContent(count(), part=slice(10)))
         10
         sage: len(BuildWordContent(count(), part=slice(10, 0, -2)))
+        doctest:...: DeprecationWarning: WordContentFromList is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
         5
     """
     if format is None:
@@ -115,7 +131,7 @@
         sage: from sage.combinat.words.word_content import BuildWordContent, is_WordContent
         sage: is_WordContent(33)
         False
-        sage: is_WordContent(BuildWordContent([0, 1, 0], sage.combinat.words.utils.id_f))
+        sage: is_WordContent(BuildWordContent([0, 1, 0], lambda x : x))
         True
     """
     return isinstance(obj, WordContent)
@@ -130,6 +146,7 @@
         TESTS::
         
             sage: c1 = sage.combinat.words.word_content.WordContentFromList([1, 2, 1, 1])
+            doctest:...: DeprecationWarning: WordContentFromList is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             sage: c2 = sage.combinat.words.word_content.WordContentFromList([1, 2, 3])
             sage: c3 = sage.combinat.words.word_content.WordContentFromList([1, 4])
             sage: c2.__cmp__(c1) > 0
@@ -156,6 +173,7 @@
         
             sage: from sage.combinat.words.word_content import BuildWordContent
             sage: list(BuildWordContent([1]).concatenate(BuildWordContent([2, 3, 4])))
+            doctest:...: DeprecationWarning: ConcatenateContent is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             [1, 2, 3, 4]
         """
         if not (haslen(self) and haslen(other)):
@@ -212,6 +230,7 @@
         ::
         
             sage: f = sage.combinat.words.word_content.WordContentFromList(range(10))
+            doctest:...: DeprecationWarning: WordContentFromList is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             sage: f._check_getitem_args(slice(None, None, None))
             slice(0, 10, 1)
             sage: f._check_getitem_args(slice(None, 0, None))
@@ -315,6 +334,7 @@
         
             sage: from itertools import count
             sage: i = sage.combinat.words.word_content.WordContentFromIterator(count())
+            doctest:...: DeprecationWarning: WordContentFromIterator is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             sage: i._check_getitem_args(slice(None, None, None))
             slice(0, None, 1)
             sage: i._check_getitem_args(slice(None, 0, None))
@@ -436,13 +456,12 @@
         TESTS::
         
             sage: c = sage.combinat.words.word_content.WordContentFromList([0, 1, 1, 2, 1])
+            doctest:...: DeprecationWarning: WordContentFromList is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             sage: c == loads(dumps(c))
             True
         """
-        # FIXME: the line below
-        #typecode = {1:'B', 2:'I', 4:'L'}[dropwhile(lambda x: x < len(parent.alphabet())/256, [1, 2, 4]).next()]
-        #from array import array
-        #self._list = array('B', imap(trans, l))
+        from sage.misc.misc import deprecation
+        deprecation('%s is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives' % self.__class__.__name__)
         self._list = map(trans, l)
     
     def __iter__(self):
@@ -450,6 +469,7 @@
         TESTS::
         
             sage: list(sage.combinat.words.word_content.WordContentFromList('012345', int)) # indirect test
+            doctest:...: DeprecationWarning: WordContentFromList is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             [0, 1, 2, 3, 4, 5]
         """
         return iter(self._list)
@@ -459,6 +479,7 @@
         TESTS::
         
             sage: len(sage.combinat.words.word_content.WordContentFromList([0, 1, 0, 0, 1]))
+            doctest:...: DeprecationWarning: WordContentFromList is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             5
         """
         return len(self._list)
@@ -469,6 +490,7 @@
         
             sage: from sage.combinat.words.word_content import WordContentFromList
             sage: w = WordContentFromList('012345', int)
+            doctest:...: DeprecationWarning: WordContentFromList is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             sage: e = WordContentFromList('', int)
             sage: w__2 = WordContentFromList('45', int)
             sage: w_2 = WordContentFromList('01', int)
@@ -547,9 +569,12 @@
         TESTS::
         
             sage: c = sage.combinat.words.word_content.WordContentFromFunction(sage.combinat.words.utils.id_f)[:10]
+            doctest:...: DeprecationWarning: WordContentFromFunction is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             sage: c == loads(dumps(c))
             True
         """
+        from sage.misc.misc import deprecation
+        deprecation('%s is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives' % self.__class__.__name__)
         self._func = func
         self._len = Infinity
         self._trans = trans
@@ -559,6 +584,7 @@
         TESTS::
         
             sage: list(sage.combinat.words.word_content.WordContentFromFunction(sage.combinat.words.utils.id_f)[:6]) # indirect test
+            doctest:...: DeprecationWarning: WordContentFromFunction is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             [0, 1, 2, 3, 4, 5]
         """
         for i in xrange(self._len) if haslen(self) else count():
@@ -569,6 +595,7 @@
         TESTS::
         
             sage: c = sage.combinat.words.word_content.WordContentFromFunction(sage.combinat.words.utils.id_f)
+            doctest:...: DeprecationWarning: WordContentFromFunction is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             sage: len(c)
             Traceback (most recent call last):
             ...
@@ -586,7 +613,9 @@
             sage: from sage.combinat.words.utils import id_f
             sage: from sage.combinat.words.word_content import WordContentFromFunction, WordContentFromList
             sage: w = WordContentFromFunction(id_f);
+            doctest:...: DeprecationWarning: WordContentFromFunction is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             sage: e = WordContentFromList('', int)
+            doctest:...: DeprecationWarning: WordContentFromList is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             sage: w__2 = WordContentFromList('45', int)
             sage: w_2 = WordContentFromList('01', int)
             sage: w__1 = WordContentFromList('01234', int)
@@ -695,12 +724,15 @@
         
             sage: from itertools import count
             sage: c = sage.combinat.words.word_content.WordContentFromIterator(count())[:10]
+            doctest:...: DeprecationWarning: WordContentFromIterator is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
         
         ::
         
             #sage: c == loads(dumps(c)) # broken because of islice
             #True
         """
+        from sage.misc.misc import deprecation
+        deprecation('%s is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives' % self.__class__.__name__)
         self._iter = iter(it)
         self._len = Infinity
         self._trans = trans
@@ -711,6 +743,7 @@
         
             sage: from itertools import count
             sage: list(sage.combinat.words.word_content.WordContentFromIterator(count())[:6]) # indirect test
+            doctest:...: DeprecationWarning: WordContentFromIterator is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             [0, 1, 2, 3, 4, 5]
         """
         return imap(self._trans, self._get_it())
@@ -721,6 +754,7 @@
         
             sage: from itertools import count
             sage: c = sage.combinat.words.word_content.WordContentFromIterator(count())
+            doctest:...: DeprecationWarning: WordContentFromIterator is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             sage: it1 = c._get_it()
             sage: it2 = c._get_it()
             sage: it1.next()
@@ -743,6 +777,7 @@
         
             sage: from itertools import count
             sage: c = sage.combinat.words.word_content.WordContentFromIterator(count())
+            doctest:...: DeprecationWarning: WordContentFromIterator is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             sage: len(c)
             Traceback (most recent call last):
             ...
@@ -760,7 +795,9 @@
             sage: from itertools import count
             sage: from sage.combinat.words.word_content import WordContentFromIterator, WordContentFromList
             sage: w = WordContentFromIterator(count())
+            doctest:...: DeprecationWarning: WordContentFromIterator is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             sage: e = WordContentFromList('', int)
+            doctest:...: DeprecationWarning: WordContentFromList is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             sage: w__2 = WordContentFromList('45', int)
             sage: w_2 = WordContentFromList('01', int)
             sage: w__1 = WordContentFromList('01234', int)
@@ -812,6 +849,7 @@
             sage: w[::2] == w_s2
             True
             sage: w[::-2] == w_s_2
+            doctest:...: DeprecationWarning: WordContentFromList is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             True
             sage: w[::0]
             Traceback (most recent call last):
@@ -863,12 +901,15 @@
         
             sage: from sage.combinat.words.word_content import ConcatenateContent, BuildWordContent
             sage: c = ConcatenateContent((BuildWordContent([1, 2]),))
+            doctest:...: DeprecationWarning: ConcatenateContent is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             sage: len(c)
             2
             sage: c = ConcatenateContent((BuildWordContent('1221', int), BuildWordContent('2112', int)))
             sage: len(c)
             8
         """
+        from sage.misc.misc import deprecation
+        deprecation('%s is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives' % self.__class__.__name__)
         self._list = l
         super(ConcatenateContent, self).__init__(self)
         self._len = sum(imap(len, self._list))
@@ -879,6 +920,7 @@
         
             sage: from sage.combinat.words.word_content import ConcatenateContent, BuildWordContent
             sage: list(ConcatenateContent((BuildWordContent('012', int), BuildWordContent([3, 4, 5])))) # indirect test
+            doctest:...: DeprecationWarning: ConcatenateContent is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             [0, 1, 2, 3, 4, 5]
         """
         for c in self._list:
@@ -893,6 +935,7 @@
         
             sage: from sage.combinat.words.word_content import ConcatenateContent, BuildWordContent
             sage: type(ConcatenateContent((BuildWordContent([1, 2]),))._get_list())
+            doctest:...: DeprecationWarning: ConcatenateContent is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             <type 'tuple'>
         """
         return self._list
@@ -905,6 +948,7 @@
         
             sage: from sage.combinat.words.word_content import ConcatenateContent, BuildWordContent
             sage: c = ConcatenateContent((BuildWordContent('1221', int), BuildWordContent('2112', int)))
+            doctest:...: DeprecationWarning: ConcatenateContent is deprecated and will be deleted in a future version of Sage; see sage.combinat.words.word_datatypes for alternatives
             sage: c(0)
             1
             sage: c(7)
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/words/word_datatypes.pxd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sage/combinat/words/word_datatypes.pxd	Fri Jul 17 23:25:52 2009 +0200
@@ -0,0 +1,9 @@
+from sage.structure.sage_object cimport SageObject
+
+# The generic class
+cdef class WordDatatype(SageObject)
+
+# finite WordDatatype
+cdef class WordDatatype_list(WordDatatype)
+cdef class WordDatatype_str(WordDatatype)
+cdef class WordDatatype_tuple(WordDatatype)
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/words/word_datatypes.pyx
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sage/combinat/words/word_datatypes.pyx	Fri Jul 17 23:25:52 2009 +0200
@@ -0,0 +1,728 @@
+r"""
+Datatypes for finite words
+"""
+#*****************************************************************************
+#       Copyright (C) 2009 Franco Saliola <saliola@gmail.com>
+#                          Vincent Delecroix <20100.delecroix@gmail.com>
+#
+#  Distributed under the terms of the GNU General Public License version 2
+#  (GPLv2)
+#
+#  The full text of the GPLv2 is available at:
+#
+#                  http://www.gnu.org/licenses/
+#*****************************************************************************
+
+from sage.structure.sage_object cimport SageObject
+
+cdef class WordDatatype(SageObject):
+    r"""
+    The generic WordDatatype class.
+
+    Any word datatype must contain two attributes (at least)::
+
+      - _parent
+      - _hash
+
+    They are automatically defined here and it's not necessary (and forbidden)
+    to define them anywhere else.
+
+    TESTS::
+
+        sage: w = Word([0,1,1,0,0,1])
+        sage: isinstance(w, sage.combinat.words.word_datatypes.WordDatatype)
+        True
+
+    """
+    cdef public _parent
+    cdef public _hash
+    pass
+
+    def __reduce__(self):
+        r"""
+        Default pickle support
+        
+        TESTS::
+
+            sage: w = Word([0,1,1,0,0,1])
+            sage: w.__reduce__()
+            (<class 'sage.combinat.words.word.FiniteWord_list'>, (Words, [0, 1, 1, 0, 0, 1]))
+        """
+        return self.__class__, (self._parent, self._data)
+
+cdef class WordDatatype_list(WordDatatype):
+    r"""
+    Datatype class for words defined by tuples.
+    """
+    cdef public list _data
+
+    def __init__(self, parent=None, data=None):
+        r"""
+        Construct a word with a given parent.
+
+        .. note::
+
+           It is slower than WordDatatype_str and WordDatatype_tuple.
+
+        INPUT:
+
+        - ``parent`` - an instance of :class:`Words_all`
+        - ``data`` - an iterable
+
+        EXAMPLES::
+
+            sage: w = Word([0,1,1,0])
+            sage: isinstance(w, sage.combinat.words.word_datatypes.WordDatatype_list)
+            True
+
+        """
+        self._parent = parent
+        if isinstance(data,list):
+            self._data = data
+        else:
+            self._data = list(data)
+        self._hash = None
+    
+    def __contains__(self, a):
+        r"""
+        Test whether ``a`` is a letter of ``self``.
+
+        INPUT:
+
+        - ``a`` - anything
+
+        OUTPUT:
+
+        - boolean
+
+        EXAMPLES::
+
+            sage: w = Word([0,1,1,0])
+            sage: 0 in w
+            True
+            sage: 3 in w
+            False
+
+        """
+        return a in self._data
+
+    def __iter__(self):
+        r"""
+        Return an iterator that iterates through the letters of self.
+
+        EXAMPLES::
+
+            sage: w = Word([0,1,1,0])
+            sage: list(iter(w))
+            [0, 1, 1, 0]
+
+        """
+        return iter(self._data)
+    
+    def __len__(self):
+        r"""
+        Return the length of the word.
+
+        .. note::
+
+           This function will be deprecated in a future version
+           of Sage. Use ``self.length()`` instead.
+
+        EXAMPLES::
+
+            sage: w = Word([0,1,1,0])
+            sage: len(w)
+            4
+
+        """
+        return len(self._data)
+
+    def length(self):
+        r"""
+        Return the length of the word.
+
+        EXAMPLES::
+
+            sage: w = Word([0,1,1,0])
+            sage: w.length()
+            4
+
+        """
+        return len(self._data)
+
+    def __getitem__(self, key):
+        r"""
+        Implements :method:``__getitem__`` for words stored as lists.
+
+        INPUT:
+
+        - ``key`` - integer
+
+        EXAMPLES::
+
+            sage: w = Word(range(100))
+            sage: w[4]
+            4
+            sage: w[-1]
+            99
+            sage: w[3:10:2]
+            word: 3579
+
+        """
+        if isinstance(key, slice):
+            return self._parent.__call__(self._data.__getitem__(key))
+        else:
+            return self._data[key]
+
+    def count(self, a):
+        r"""
+        Returns the number of occurrences of the letter ``a`` in the word
+        ``self``.
+
+        INPUT:
+
+        -  ``a`` - a letter
+
+        OUTPUT:
+
+        - integer
+
+        EXAMPLES::
+
+            sage: w = Word([0,1,1,0,1])
+            sage: w.count(0)
+            2
+            sage: w.count(1)
+            3
+            sage: w.count(2)
+            0
+
+        """
+        return self._data.count(a)
+
+cdef class WordDatatype_str(WordDatatype):
+    """
+    Datatype for words defined by strings.
+    """
+    cdef public str _data
+    
+    # TODO : allow initialization from non string data
+    def __init__(self, parent=None, data=None):
+        r"""
+        Construct a word with parent ``parent`` from the string ``data``.
+
+        INPUT:
+
+        - ``parent`` - instance of :class:`Words_all`
+        - ``data`` - string
+
+        EXAMPLES::
+
+            sage: w = Word("abba")
+            sage: isinstance(w, sage.combinat.words.word_datatypes.WordDatatype_str)
+            True
+
+        """
+        self._parent = parent
+        if isinstance(data, str):
+            self._data = data
+        else:
+            self._data = "".join(map(str,data))
+        self._hash = None
+
+    def __iter__(self):
+        r"""
+        Return an iterator that iterates through the letters of ``self``.
+
+        EXAMPLES::
+
+            sage: w = Word('abba')
+            sage: list(iter(w))
+            ['a', 'b', 'b', 'a']
+
+        """
+        return iter(self._data)
+
+    def __contains__(self, a):
+        r"""
+        Test whether ``a`` is a letter of ``self``.
+
+        INPUT:
+
+        - ``a`` - anything
+
+        EXAMPLES::
+
+            sage: w = Word('abba')
+            sage: 'a' in w
+            True
+            sage: 'c' in w
+            False
+
+        """
+        # we need to override the non standard comportement of 
+        # the comportment of the __contains__ of python str
+        if not isinstance(a, str):
+            return False
+        if len(a) != 1:
+            return False
+        else:
+            return a in self._data
+
+    cpdef _has_factor_naive(self, w):
+        r"""
+        A naive test for testing whether the word contains ``w`` as a factor.
+
+        .. note::
+           
+           This just wraps Python's builtin :method:`__contains__` for :class:`str`.
+
+        INPUT:
+
+        - ``w`` - a word, or something that behaves like one (list, tuple, str, ...)
+
+        OUTPUT:
+
+        - boolean
+
+        EXAMPLES::
+
+            sage: w = Word('abba')
+            sage: w._has_factor_naive('ba')
+            True
+            sage: w._has_factor_naive('bab')
+            False
+
+        """
+        if isinstance(w, WordDatatype_str):
+            return w._data in self._data
+        elif isinstance(w, str):
+            return w in self._data
+        raise ValueError
+
+    cpdef find(self, letter, start=None, stop=None):
+        """
+        Return the position of the first occurrence of ``letter`` in
+        ``self``.
+
+        INPUT:
+
+        -  ``letter`` - the letter to search for
+        - ``start`` - [default: 0] the position in which to start searching
+        - ``stop`` - [default: None] the position in which to stop searching
+
+        OUTPUT:
+
+        - nonnegative integer if the ``letter`` occurs in the word
+        - ``-1`` if ``letter`` does not occur in the word. (This is the same
+          behaviour as Python's :class:`str`.)
+
+        EXAMPLES::
+
+            sage: w = Word("abbabaabababa")
+            sage: w.find("a")
+            0
+            sage: w.find("a", 4)
+            5
+            sage: w.find("a", 4, 5)
+            -1
+
+        """
+        if start is None:
+            start = 0
+        if stop is None:
+            stop = len(self._data)
+        return self._data.find(letter, start, stop)
+    
+    def rfind(self, letter, start=None, stop=None):
+        """
+        Similar to :method:`find`, but searches through the word in
+        reverse.
+        
+        INPUT:
+
+        - ``letter`` - the letter to search for
+        - ``start`` - [default: None] the position in which to start searching
+        - ``stop`` - [default: None] the position in which to stop searching
+
+        OUTPUT:
+
+        - nonnegative integer if the ``letter`` occurs in the word
+        - ``-1`` if ``letter`` does not occur in the word. (This is the same
+          behaviour as Python's :class:`str`.)
+
+        EXAMPLES::
+
+            sage: w = Word("abbabaabababa")
+            sage: w.rfind("a")
+            12
+            sage: w.rfind("a", 4, 8)
+            6
+            sage: w.rfind("a", 4, 5)
+            -1
+
+        """
+        if len(letter) != 1:
+           return False
+        if start is None:
+            start = 0
+        if stop is None:
+            stop = len(self._data)
+        return self._data.rfind(letter, start, stop)
+
+    def __len__(self):
+        r"""
+        Return the length of the word.
+
+        .. note::
+
+           This function will be deprecated in a future version
+           of Sage. Use ``self.length()`` instead.
+
+        EXAMPLES::
+
+            sage: w = Word("abbabaabababa")
+            sage: len(w)
+            13
+
+        """
+        return len(self._data)
+
+    def length(self):
+        r"""
+        Return the length of the word.
+
+        EXAMPLES::
+
+            sage: w = Word("abbabaabababa")
+            sage: w.length()
+            13
+
+        """
+        return len(self._data)
+
+    def __getitem__(self, key):
+        r"""
+        Implements the :method:`__getitem__`.
+
+        TESTS::
+
+            sage: alphabet = map(chr, range(97,123))
+            sage: w = Word(alphabet)
+            sage: w[4]
+            'e'
+            sage: w[-1]
+            'z'
+            sage: w[3:10:2]
+            word: dfhj
+            sage: all(chr(i+97) == w[i] for i in range(w.length()))
+            True
+
+        """
+        if isinstance(key, slice):
+            return self._parent(self._data[key])
+        return self._data[key]
+
+    def count(self, letter):
+        r"""
+        Count the number of occurences of ``letter``.
+
+        INPUT:
+
+        - ``letter`` - a letter
+
+        OUTPUT:
+
+        - integer
+
+        EXAMPLES::
+
+            sage: w = Word("abbabaabababa")
+            sage: w.count('a')
+            7
+            sage: w.count('b')
+            6
+            sage: w.count('c')
+            0
+        
+        """
+        return self._data.count(letter)
+
+    def is_suffix(self, other):
+        r"""
+        Test whether ``self`` is a suffix of ``other``.
+
+        INPUT:
+
+        - ``other`` - a word (an instance of :class:`Word_class`) or a
+          :class:`str`.
+
+        OUTPUT:
+
+        - boolean
+         
+        EXAMPLES::
+
+            sage: w = Word("abbabaabababa")
+            sage: u = Word("ababa")
+            sage: w.is_suffix(u)
+            False
+            sage: u.is_suffix(w)
+            True
+            sage: u.is_suffix("abbabaabababa")
+            True
+
+        TESTS::
+
+            sage: w = Word("abbabaabababa")
+            sage: u = Word(['a','b','a','b','a'])
+            sage: w.is_suffix(u)
+            False
+            sage: u.is_suffix(w)
+            True
+
+        """
+        if isinstance(other, WordDatatype_str):
+            return other._data.endswith(self._data)
+        elif isinstance(other, str):
+            return other.endswith(self._data)
+        else:
+            return super(WordDatatype_str, self).is_suffix(other)
+                    
+    def has_suffix(self, other):
+        """
+        Test whether ``self`` has ``other`` as a suffix.
+
+        INPUT:
+
+        - ``other`` - a word (an instance of :class:`Word_class`) or a
+          :class:`str`.
+
+        OUTPUT:
+
+        - boolean
+         
+        EXAMPLES::
+
+            sage: w = Word("abbabaabababa")
+            sage: u = Word("ababa")
+            sage: w.has_suffix(u)
+            True
+            sage: u.has_suffix(w)
+            False
+            sage: u.has_suffix("ababa")
+            True
+
+        """
+        if isinstance(other, WordDatatype_str):
+            return self._data.endswith(other._data)
+        elif isinstance(other, str):
+            return self._data.endswith(other)
+        else:
+            return super(WordDatatype_str, self).has_suffix(other)
+       
+    def is_prefix(self, other):
+        r"""
+        Test whether ``self`` is a prefix of ``other``.
+
+        INPUT:
+
+        - ``other`` - a word (an instance of :class:`Word_class`) or a
+          :class:`str`.
+
+        OUTPUT:
+
+        - boolean
+         
+        EXAMPLES::
+
+            sage: w = Word("abbabaabababa")
+            sage: u = Word("abbab")
+            sage: w.is_prefix(u)
+            False
+            sage: u.is_prefix(w)
+            True
+            sage: u.is_prefix("abbabaabababa")
+            True
+
+        TESTS::
+
+            sage: ab = Word('ab')
+            sage: abba = Word(['a','b','b','a'])
+            sage: ab.is_prefix(abba)
+            True
+            sage: abba.is_prefix(ab)
+            False
+
+        """
+        if isinstance(other, WordDatatype_str):
+            return other._data.startswith(self._data)
+        if isinstance(other ,str):
+            return other.startswith(self._data)
+        else:
+            return super(WordDatatype_str, self).is_prefix(other)
+
+    def has_prefix(self, other):
+        r"""
+        Test whether ``self`` has ``other`` as a prefix.
+
+        INPUT:
+
+        - ``other`` - a word (an instance of :class:`Word_class`) or a
+          :class:`str`.
+
+        OUTPUT:
+
+        - boolean
+         
+        EXAMPLES::
+
+            sage: w = Word("abbabaabababa")
+            sage: u = Word("abbab")
+            sage: w.has_prefix(u)
+            True
+            sage: u.has_prefix(w)
+            False
+            sage: u.has_prefix("abbab")
+            True
+
+        TESTS::
+
+            sage: ab = Word('ab')
+            sage: abba = Word(['a','b','b','a'])
+            sage: ab.has_prefix(abba)
+            False
+            sage: abba.has_prefix(ab)
+            True
+
+        """
+        if isinstance(other, WordDatatype_str):
+            return self._data.startswith(other._data)
+        if isinstance(other, str):
+            return self._data.startswith(other)
+        else:
+            return super(WordDatatype_str, self).has_prefix(other)
+
+cdef class WordDatatype_tuple(WordDatatype):
+    r"""
+    Datatype class for words defined by tuples.
+    """
+    cdef public tuple _data
+    
+    def __init__(self, parent=None, data=None):
+        r"""
+        Construct a word with parent ``parent`` from an iterable ``data``.
+
+        INPUT:
+
+        - ``parent`` - instance of :class:`Words_all`
+        - ``data`` - iterable
+
+        EXAMPLES::
+
+            sage: w = Word((0,1,1,0))
+            sage: isinstance(w, sage.combinat.words.word_datatypes.WordDatatype_tuple)
+            True
+            sage: u = Word([0,1,1,0], datatype='tuple')
+            sage: isinstance(u, sage.combinat.words.word_datatypes.WordDatatype_tuple)
+            True
+
+        """
+        self._parent = parent
+        if isinstance(data,tuple):
+            self._data = data   
+        else:
+            self._data = tuple(data)
+        self._hash = None
+
+    def __iter__(self):
+        r"""
+        Return an iterator that iterates through the letters of self.
+
+        EXAMPLES::
+
+            sage: w = Word((0,1,1,0))
+            sage: list(iter(w))
+            [0, 1, 1, 0]
+
+        """
+        return iter(self._data)
+
+    def __len__(self):
+        r"""
+        Return the length of the word.
+
+        .. note::
+
+           This function will be deprecated in a future version
+           of Sage. Use ``self.length()`` instead.
+
+        EXAMPLES::
+
+            sage: w = Word((0,1,1,0))
+            sage: len(w)
+            4
+
+        """
+        return len(self._data)
+
+    def length(self):
+        r"""
+        Return the length of the word.
+
+        EXAMPLES::
+
+            sage: w = Word((0,1,1,0))
+            sage: w.length()
+            4
+
+        """
+        return len(self._data)
+
+    def __contains__(self, a):
+        r"""
+        Test whether ``a`` is a letter of ``self``.
+
+        INPUT:
+
+        - ``a`` - anything
+
+        EXAMPLES::
+
+            sage: w = Word((0,1,1,0))
+            sage: 0 in w
+            True
+            sage: 3 in w
+            False
+
+        """
+        return a in self._data
+
+    def __getitem__(self, key):
+        r"""
+        Implements ``__getitem__`` for words stored as tuples.
+
+        INPUT:
+
+        - ``key`` - an integer
+
+        OUTPUT:
+
+        - can be anything (an object contained in the word)
+
+        EXAMPLES::
+
+            sage: w = Word(tuple(range(100)))
+            sage: w[4]
+            4
+            sage: w[-1]
+            99
+            sage: w[3:10:2]
+            word: 3579
+            sage: all(w[i] == i for i in range(100))
+            True
+
+        """
+        if isinstance(key, slice):
+            return self._parent(self._data[key])
+        return self._data[key]
diff -r ca1f31d6f6bf -r 77b673b9aca3 sage/combinat/words/word_generators.py
--- a/sage/combinat/words/word_generators.py	Thu Jul 09 15:14:36 2009 -0700
+++ b/sage/combinat/words/word_generators.py	Fri Jul 17 23:25:52 2009 +0200
@@ -1,10 +1,28 @@
 # coding=utf-8
-"""
-Word generators
+r"""
+A collection of constructors of common words
+
+AUTHORS:
+
+    - Franco Saliola (2008-12-17): merged into sage
+    - Sebastien Labbe (2008-12-17): merged into sage
+    - Arnaud Bergeron (2008-12-17): merged into sage
+    - Amy Glen (2008-12-17): merged into sage
+
+USE:
+
+To see a list of all word constructors, type “words.” and then press the tab
+key. The documentation for each constructor includes information about each
+word, which provides a useful reference.
+
+EXAMPLES::
+
+    sage: t = words.ThueMorseWord(); t
+    Thue-Morse word over Ordered Alphabet [0, 1]
 """
 #*****************************************************************************
 #       Copyright (C) 2008 Franco Saliola <saliola@gmail.com>,
-#                          Sébastien Labbé <slabqc@gmail.com>,
+#                          Sebastien Labbe <slabqc@gmail.com>,
 #                          Arnaud Bergeron <abergeron@gmail.com>,
 #                          Amy Glen <amy.glen@gmail.com>
 #
@@ -17,20 +35,20 @@
 from itertools import cycle, count
 from random import randint
 from sage.structure.sage_object import SageObject
+from sage.rings.all import ZZ
+from sage.rings.infinity import Infinity
+from sage.combinat.words.word import (FiniteWord_class, Word_class,
+        FiniteWord_list, Factorization)
+from sage.combinat.words.words import Words
+from sage.combinat.words.morphism import WordMorphism
 from sage.rings.arith import gcd
-from sage.combinat.words.word import FiniteWord_over_OrderedAlphabet, InfiniteWord_over_OrderedAlphabet, is_Word, is_FiniteWord
-from sage.combinat.words.words import Words
-from sage.combinat.words.alphabet import OrderedAlphabet
-from sage.combinat.words.utils import *
-from sage.combinat.words.morphism import WordMorphism
 
 def _build_tab(sym, tab, W):
     r"""
-    Internal function building a coding table for the phi_inv_tab
-    function.
+    Internal function building a coding table for the ``phi_inv_tab`` function.
     
     TESTS::
-    
+
         sage: from sage.combinat.words.word_generators import _build_tab
         sage: _build_tab(1, [], Words([1, 2]))
         [1]
@@ -58,92 +76,315 @@
         res.append((w[-1] % W.size_of_alphabet()) + 1)
     return res
 
+class LowerChristoffelWord(FiniteWord_list):
+    r"""
+    Returns the lower Christoffel word of slope `p/q`, where `p` and
+    `q` are relatively prime non-negative integers, over the given
+    two-letter alphabet.
+
+    The *Christoffel word of slope `p/q`* is obtained from the
+    Cayley graph of `\ZZ/(p+q)\ZZ` with generator `q` as
+    follows. If `u \rightarrow v` is an edge in the Cayley graph, then
+    `v = u + p \mod{p+q}`. Label the edge `u \rightarrow v` by
+    ``alphabet[1]`` if `u < v` and ``alphabet[0]`` otherwise. The Christoffel
+    word is the word obtained by reading the edge labels along the
+    cycle beginning from 0.
+
+    EXAMPLES::
+
+        sage: w = words.LowerChristoffelWord(1,0); w
+        Lower Christoffel word of slope 1/0 over Ordered Alphabet [0, 1]
+        sage: print w
+        word: 1
+    
+    ::
+        
+        sage: w = words.LowerChristoffelWord(0,1,'xy'); w
+        Lower Christoffel word of slope 0/1 over Ordered Alphabet ['x', 'y']
+        sage: print w
+        word: x
+    
+    ::
+        
+        sage: w = words.LowerChristoffelWord(1,1); w
+        Lower Christoffel word of slope 1/1 over Ordered Alphabet [0, 1]
+        sage: print w
+        word: 01
+    
+    ::
+        
+        sage: w = words.LowerChristoffelWord(4,7); w
+        Lower Christoffel word of slope 4/7 over Ordered Alphabet [0, 1]
+        sage: print w
+        word: 00100100101
+    
+    ::
+
+        sage: w = words.LowerChristoffelWord(4,7,alphabet='ab'); w
+        Lower Christoffel word of slope 4/7 over Ordered Alphabet ['a', 'b']
+        sage: print w
+        word: aabaabaabab
+    """
+
+    def __init__(self, p, q, alphabet=(0,1)):
+        r"""
+        TESTS::
+
+            sage: words.LowerChristoffelWord(4,8)
+            Traceback (most recent call last):
+            ...
+            ValueError: 4 and 8 are not relatively prime
+            sage: words.LowerChristoffelWord(17, 39, 'xyz')
+            Traceback (most recent call last):
+            ...
+            ValueError: alphabet must contain exactly two distinct elements
+            sage: w = words.LowerChristoffelWord(4,7)
+            sage: w2 = loads(dumps(w))
+            sage: w == w2
+            True
+            sage: type(w2)
+            <class 'sage.combinat.words.word_generators.LowerChristoffelWord'>
+            sage: _ = w2.standard_factorization() # hackish test for self.__p and self.__q
+        """
+        if len(set(alphabet)) != 2:
+            raise ValueError, "alphabet must contain exactly two distinct elements"
+        # Compute gcd of p, q; raise TypeError if not 1.
+        if gcd(p,q) != 1:
+            raise ValueError, "%s and %s are not relatively prime" % (p, q)
+        # Compute the Christoffel word
+        w = []
+        u = 0
+        if (p, q) == (0, 1):
+            w = [alphabet[0]]
+        else:
+            for i in range(p + q):
+                v = (u+p) % (p+q)
+                new_letter = alphabet[0] if u < v else alphabet[1]
+                w.append(new_letter)
+                u = v
+        super(LowerChristoffelWord, self).__init__(Words(alphabet), w)
+        self.__p = p
+        self.__q = q
+
+    def __repr__(self):
+        r"""
+        EXAMPLES::
+
+            sage: w = words.LowerChristoffelWord(4,7,alphabet='ab'); w
+            Lower Christoffel word of slope 4/7 over Ordered Alphabet ['a', 'b']
+        """
+        return "Lower Christoffel word of slope %s/%s over %s" % (self.__p, self.__q, self.parent().alphabet())
+
+    def markoff_number(self):
+        r"""
+        Returns the Markoff number associated to the Christoffel word self.
+        
+        The *Markoff number* of a Christoffel word `w` is `trace(M(w))/3`,
+        where `M(w)` is the `2\times 2` matrix obtained by applying the
+        morphism:
+        0 -> matrix(2,[2,1,1,1])
+        1 -> matrix(2,[5,2,2,1])
+        
+        EXAMPLES::
+
+            sage: w0 = words.LowerChristoffelWord(4,7) 
+            sage: w1, w2 = w0.standard_factorization()
+            sage: (m0,m1,m2) = (w.markoff_number() for w in (w0,w1,w2))
+            sage: (m0,m1,m2)
+            (294685, 13, 7561)
+            sage: m0**2 + m1**2 + m2**2 == 3*m0*m1*m2
+            True
+        """
+        from sage.matrix.constructor import matrix
+        eta = {0:matrix(2,[2,1,1,1]), 1:matrix(2,[5,2,2,1])}
+        M = matrix(2,[1,0