Example #1
0
def build_alphabet(data=None, names=None, name=None):
    r"""
    Returns an object representing an ordered alphabet.

    EXAMPLES:

    If the argument is a Set, it just returns it::

        sage: build_alphabet(ZZ) is ZZ
        True
        sage: F = FiniteEnumeratedSet('abc')
        sage: build_alphabet(F) is F
        True

    If a list, tuple or string is provided, then it builds a proper Sage class
    (:class:`~sage.sets.totally_ordered_finite_set.TotallyOrderedFiniteSet`)::

        sage: build_alphabet([0,1,2])
        {0, 1, 2}
        sage: F = build_alphabet('abc'); F
        {'a', 'b', 'c'}
        sage: print type(F).__name__
        TotallyOrderedFiniteSet_with_category

    If no data is provided, ``name`` may be a string which describe an alphabet.
    The available names decompose into two families. The first one are 'positive
    integers', 'PP', 'natural numbers' or 'NN' which refer to standard set of
    numbers::

        sage: build_alphabet(name="positive integers")
        Positive integers
        sage: build_alphabet(name="PP")
        Positive integers
        sage: build_alphabet(name="natural numbers")
        Non negative integers
        sage: build_alphabet(name="NN")
        Non negative integers

    The other families for the option ``name`` are among 'lower', 'upper',
    'space', 'underscore', 'punctuation', 'printable', 'binary', 'octal',
    'decimal', 'hexadecimal', 'radix64' which refer to standard set of
    charaters. Theses names may be combined by separating them by a space::

        sage: build_alphabet(name="lower")
        {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}
        sage: build_alphabet(name="hexadecimal")
        {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}
        sage: build_alphabet(name="decimal punctuation")
        {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' ', ',', '.', ';', ':', '!', '?'}

    In the case the alphabet is built from a list or a tuple, the order on the
    alphabet is given by the elements themselves::

        sage: A = build_alphabet([0,2,1])
        sage: A(0) < A(2)
        True
        sage: A(2) < A(1)
        False

    If a different order is needed, you may use
    :class:`~sage.sets.totally_ordered_finite_set.TotallyOrderedFiniteSet` and
    set the option ``facade`` to ``False``. That way, the comparison fits the
    order of the input::

        sage: A = TotallyOrderedFiniteSet([4,2,6,1], facade=False)
        sage: A(4) < A(2)
        True
        sage: A(1) < A(6)
        False

    Be careful, the element of the set in the last example are no more
    integers and do not compare equal with integers::

        sage: type(A.an_element())
        <class 'sage.sets.totally_ordered_finite_set.TotallyOrderedFiniteSet_with_category.element_class'>
        sage: A(1) == 1
        False
        sage: 1 == A(1)
        False
    """
    if data in Sets():
        return data
    if isinstance(data, (int, long, Integer)):
        if names is None:
            from sage.sets.integer_range import IntegerRange
            return IntegerRange(Integer(data))
        elif len(names) == data:
            return TotallyOrderedFiniteSet(data)
        elif isinstance(names, str):
            return TotallyOrderedFiniteSet(
                [names + '%d' % i for i in xrange(data)])
        raise ValueError("not possible")
    elif data == Infinity:
        if names is None:
            return NonNegativeIntegers()
        else:
            Family(NonNegativeIntegers(), lambda i: 'x%d' % i)
    if data is None and name is None:
        from sage.structure.parent import Set_PythonType
        return Set_PythonType(object)
    if data is None:
        if name == "positive integers" or name == "PP":
            from sage.sets.positive_integers import PositiveIntegers
            return PositiveIntegers()
        elif name == "natural numbers" or name == "NN":
            return NonNegativeIntegers()
        else:
            names = name.split(' ')
            data = []
            for name in names:
                if name in set_of_letters:
                    data.extend(list(set_of_letters[name]))
                else:
                    raise TypeError("name is not recognized")
            return TotallyOrderedFiniteSet(data)
        raise TypeError("name is not recognized")
    elif isinstance(data, (tuple, list, str)):
        return TotallyOrderedFiniteSet(data)
Example #2
0
def build_alphabet(data=None, names=None, name=None):
    r"""
    Return an object representing an ordered alphabet.

    INPUT:

    - ``data`` -- the letters of the alphabet; it can be:

      * a list/tuple/iterable of letters; the iterable may be infinite
      * an integer `n` to represent `\{1, \ldots, n\}`, or infinity to
        represent `\NN`

    - ``names`` -- (optional) a list for the letters (i.e. variable names) or
      a string for prefix for all letters; if given a list, it must have the
      same cardinality as the set represented by ``data``

    - ``name`` -- (optional) if given, then return a named set and can be
      equal to : ``'lower', 'upper', 'space',
      'underscore', 'punctuation', 'printable', 'binary', 'octal', 'decimal',
      'hexadecimal', 'radix64'``.

      You can use many of them at once, separated by spaces : ``'lower
      punctuation'`` represents the union of the two alphabets ``'lower'`` and
      ``'punctuation'``.

      Alternatively, ``name`` can be set to ``"positive integers"`` (or
      ``"PP"``) or ``"natural numbers"`` (or ``"NN"``).

      ``name`` cannot be combined with ``data``.

    EXAMPLES:

    If the argument is a Set, it just returns it::

        sage: build_alphabet(ZZ) is ZZ
        True
        sage: F = FiniteEnumeratedSet('abc')
        sage: build_alphabet(F) is F
        True

    If a list, tuple or string is provided, then it builds a proper Sage class
    (:class:`~sage.sets.totally_ordered_finite_set.TotallyOrderedFiniteSet`)::

        sage: build_alphabet([0,1,2])
        {0, 1, 2}
        sage: F = build_alphabet('abc'); F
        {'a', 'b', 'c'}
        sage: print(type(F).__name__)
        TotallyOrderedFiniteSet_with_category

    If an integer and a set is given, then it constructs a
    :class:`~sage.sets.totally_ordered_finite_set.TotallyOrderedFiniteSet`::

        sage: build_alphabet(3, ['a','b','c'])
        {'a', 'b', 'c'}

    If an integer and a string is given, then it considers that string as a
    prefix::

        sage: build_alphabet(3, 'x')
        {'x0', 'x1', 'x2'}

    If no data is provided, ``name`` may be a string which describe an alphabet.
    The available names decompose into two families. The first one are 'positive
    integers', 'PP', 'natural numbers' or 'NN' which refer to standard set of
    numbers::

        sage: build_alphabet(name="positive integers")
        Positive integers
        sage: build_alphabet(name="PP")
        Positive integers
        sage: build_alphabet(name="natural numbers")
        Non negative integers
        sage: build_alphabet(name="NN")
        Non negative integers

    The other families for the option ``name`` are among 'lower', 'upper',
    'space', 'underscore', 'punctuation', 'printable', 'binary', 'octal',
    'decimal', 'hexadecimal', 'radix64' which refer to standard set of
    charaters. Theses names may be combined by separating them by a space::

        sage: build_alphabet(name="lower")
        {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}
        sage: build_alphabet(name="hexadecimal")
        {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}
        sage: build_alphabet(name="decimal punctuation")
        {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' ', ',', '.', ';', ':', '!', '?'}

    In the case the alphabet is built from a list or a tuple, the order on the
    alphabet is given by the elements themselves::

        sage: A = build_alphabet([0,2,1])
        sage: A(0) < A(2)
        True
        sage: A(2) < A(1)
        False

    If a different order is needed, you may use
    :class:`~sage.sets.totally_ordered_finite_set.TotallyOrderedFiniteSet` and
    set the option ``facade`` to ``False``. That way, the comparison fits the
    order of the input::

        sage: A = TotallyOrderedFiniteSet([4,2,6,1], facade=False)
        sage: A(4) < A(2)
        True
        sage: A(1) < A(6)
        False

    Be careful, the element of the set in the last example are no more
    integers and do not compare equal with integers::

        sage: type(A.an_element())
        <class 'sage.sets.totally_ordered_finite_set.TotallyOrderedFiniteSet_with_category.element_class'>
        sage: A(1) == 1
        False
        sage: 1 == A(1)
        False

    We give an example of an infinite alphabet indexed by the positive
    integers and the prime numbers::

        sage: build_alphabet(oo, 'x')
        Lazy family (x(i))_{i in Non negative integers}
        sage: build_alphabet(Primes(), 'y')
        Lazy family (y(i))_{i in Set of all prime numbers: 2, 3, 5, 7, ...}

    TESTS::

        sage: Alphabet(3, name="punctuation")
        Traceback (most recent call last):
        ...
        ValueError: name cannot be specified with any other argument
        sage: Alphabet(8, ['e']*10)
        Traceback (most recent call last):
        ...
        ValueError: invalid value for names
        sage: Alphabet(8, x)
        Traceback (most recent call last):
        ...
        ValueError: invalid value for names
        sage: Alphabet(name=x, names="punctuation")
        Traceback (most recent call last):
        ...
        ValueError: name cannot be specified with any other argument
        sage: Alphabet(x)
        Traceback (most recent call last):
        ...
        ValueError: unable to construct an alphabet from the given parameters
    """
    # If both 'names' and 'data' are defined
    if name is not None and (data is not None or names is not None):
        raise ValueError("name cannot be specified with any other argument")

    # Swap arguments if we need to to try and make sure we have "good" user input
    if isinstance(names, integer_types + (Integer,)) or names == Infinity \
            or (data is None and names is not None):
        data,names = names,data

    # data is an integer
    if isinstance(data, integer_types + (Integer,)):
        if names is None:
            from sage.sets.integer_range import IntegerRange
            return IntegerRange(Integer(data))
        if isinstance(names, str):
            return TotallyOrderedFiniteSet([names + '%d'%i for i in range(data)])
        if len(names) == data:
            return TotallyOrderedFiniteSet(names)
        raise ValueError("invalid value for names")

    if data == Infinity:
        data = NonNegativeIntegers()

    # data is an iterable
    if isinstance(data, (tuple, list, str, range)) or data in Sets():
        if names is not None:
            if not isinstance(names, str):
                raise TypeError("names must be a string when data is a set")
            return Family(data, lambda i: names + str(i), name=names)
        if data in Sets():
            return data
        return TotallyOrderedFiniteSet(data)

    # Alphabet defined from a name
    if name is not None:
        if not isinstance(name, str):
            raise TypeError("name must be a string")
        if name == "positive integers" or name == "PP":
            from sage.sets.positive_integers import PositiveIntegers
            return PositiveIntegers()
        if name == "natural numbers" or name == "NN":
            return NonNegativeIntegers()

        data = []
        for alpha_name in name.split(' '):
            try:
                data.extend(list(set_of_letters[alpha_name]))
            except KeyError:
                raise TypeError("name is not recognized")
        return TotallyOrderedFiniteSet(data)

    # Alphabet(**nothing**)
    if data is None: # name is also None
        from sage.structure.parent import Set_PythonType
        return Set_PythonType(object)

    raise ValueError("unable to construct an alphabet from the given parameters")
Example #3
0
class Words_all(InfiniteAbstractCombinatorialClass):
    r"""
    TESTS::

        sage: from sage.combinat.words.words import Words_all
        sage: list(Words_all())
        Traceback (most recent call last):
        ...
        NotImplementedError
        sage: Words_all().list()
        Traceback (most recent call last):
        ...
        NotImplementedError: infinite list
        sage: Words_all().cardinality()
        +Infinity

    We would like the instance of this class to be unique::

        sage: Words() is Words()   # todo: not implemented
        True
    """
    @lazy_attribute
    def _element_classes(self):
        r"""
        Returns a dictionary that gives the class of the element of self.

        The word may be finite, infinite or of unknown length.
        Its data may be str, list, tuple, a callable or an iterable.
        For callable and iterable, the data may be cached.

        TESTS::

            sage: d = Words()._element_classes
            sage: type(d)
            <type 'dict'>
            sage: len(d)
            13
            sage: e = Words('abcdefg')._element_classes
            sage: d == e
            True
        """
        import sage.combinat.words.word as word
        return {
            'FiniteWord_list': word.FiniteWord_list,
            'FiniteWord_str': word.FiniteWord_str,
            'FiniteWord_tuple': word.FiniteWord_tuple,
            'FiniteWord_callable_with_caching':
            word.FiniteWord_callable_with_caching,
            'FiniteWord_callable': word.FiniteWord_callable,
            'FiniteWord_iter_with_caching': word.FiniteWord_iter_with_caching,
            'FiniteWord_iter': word.FiniteWord_iter,
            'InfiniteWord_callable_with_caching':
            word.InfiniteWord_callable_with_caching,
            'InfiniteWord_callable': word.InfiniteWord_callable,
            'InfiniteWord_iter_with_caching':
            word.InfiniteWord_iter_with_caching,
            'InfiniteWord_iter': word.InfiniteWord_iter,
            'Word_iter_with_caching': word.Word_iter_with_caching,
            'Word_iter': word.Word_iter
        }

    def __call__(self,
                 data=None,
                 length=None,
                 datatype=None,
                 caching=True,
                 **kwds):
        r"""
        Construct a new word object with parent self.

        INPUT:

        -  ``data`` - (default: None) list, string, tuple, iterator, None
           (shorthand for []), or a callable defined on [0,1,...,length].

        -  ``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" or "pickled_function". 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:

            We only check that the first 40 letters of the word are
            actually in the alphabet. This is a quick check implemented to
            test for small programming errors. Since we also support
            infinite words, we cannot really implement a more accurate
            check.

        EXAMPLES::

            sage: from itertools import count
            sage: Words()(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: Words(range(10))(count())
            Traceback (most recent call last):
            ...
            ValueError: 10 not in alphabet!
            sage: Words()("abba")
            word: abba
            sage: Words("ab")("abba")
            word: abba
            sage: Words("ab")("abca")
            Traceback (most recent call last):
            ...
            ValueError: c not in alphabet!
        """
        from sage.combinat.words.word import Word
        kwds['data'] = data
        kwds['length'] = length
        kwds['datatype'] = datatype
        kwds['caching'] = caching
        #kwds['alphabet'] = self

        # The function _construct_word handles the construction of the words.
        w = self._construct_word(**kwds)
        self._check(w)
        return w

    def _construct_word(self,
                        data=None,
                        length=None,
                        datatype=None,
                        caching=True):
        r"""
        Construct a word.

        INPUT:

        -  ``data`` - (default: None) list, string, tuple, iterator, None
           (shorthand for []), or a callable defined on [0,1,...,length].

        -  ``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: Words()._construct_word()
            word:

        Word with string::

            sage: Words()._construct_word("abbabaab")
            word: abbabaab

        Word with string constructed from other types::

            sage: Words()._construct_word([0,1,1,0,1,0,0,1], datatype="str")
            word: 01101001
            sage: Words()._construct_word((0,1,1,0,1,0,0,1), datatype="str")
            word: 01101001

        Word with list::

            sage: Words()._construct_word([0,1,1,0,1,0,0,1])
            word: 01101001

        Word with list constructed from other types::

            sage: Words()._construct_word("01101001", datatype="list")
            word: 01101001
            sage: Words()._construct_word((0,1,1,0,1,0,0,1), datatype="list")
            word: 01101001

        Word with tuple::

            sage: Words()._construct_word((0,1,1,0,1,0,0,1))
            word: 01101001

        Word with tuple constructed from other types::

            sage: Words()._construct_word([0,1,1,0,1,0,0,1], datatype="tuple")
            word: 01101001
            sage: Words()._construct_word("01101001", datatype="str")
            word: 01101001

        Word with iterator::

            sage: from itertools import count
            sage: Words()._construct_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: Words()._construct_word(iter("abbabaab")) # iterators default to infinite words
            word: abbabaab
            sage: Words()._construct_word(iter("abbabaab"), length="unknown")
            word: abbabaab
            sage: Words()._construct_word(iter("abbabaab"), length="finite")
            word: abbabaab

        Word with function (a 'callable')::

            sage: f = lambda n : add(Integer(n).digits(2)) % 2
            sage: Words()._construct_word(f)
            word: 0110100110010110100101100110100110010110...
            sage: Words()._construct_word(f, length=8)
            word: 01101001

        Word over a string with a parent::

            sage: w = Words('abc')._construct_word("abbabaab"); w
            word: abbabaab
            sage: w.parent()
            Words over {'a', 'b', 'c'}

        The default parent is the combinatorial class of all words::

            sage: w = Words()._construct_word("abbabaab"); w
            word: abbabaab
            sage: w.parent()
            Words

        Creation of a word from a word::

            sage: Words([0,1,2,3])(Words([2,3])([2,2,2,3,3,2]))
            word: 222332
            sage: _.parent()
            Words over {0, 1, 2, 3}

        ::

            sage: Words([3,2,1])(Words([2,3])([2,2,2,3,3,2]))
            word: 222332
            sage: _.parent()
            Words over {3, 2, 1}

        Construction of a word from a word when the parents are the same::

            sage: W = Words()
            sage: w = W(range(8))
            sage: z = W(w)
            sage: w is z
            True

        Construction of a word path from a finite word::

            sage: W = Words('abcd')
            sage: P = WordPaths('abcd')
            sage: w = W('aaab')
            sage: P(w)
            Path: aaab

        Construction of a word path from a Christoffel word::

            sage: w = words.ChristoffelWord(5,8)
            sage: w
            word: 0010010100101
            sage: P = WordPaths([0,1,2,3])
            sage: P(w)
            Path: 0010010100101

        Construction of a word represented by a list from a word
        represented by a str ::

            sage: w = Word('ababbbabab')
            sage: type(w)
            <class 'sage.combinat.words.word.FiniteWord_str'>
            sage: z = Word(w, datatype='list')
            sage: type(z)
            <class 'sage.combinat.words.word.FiniteWord_list'>
            sage: y = Word(w, alphabet='abc', datatype='list')
            sage: type(y)
            <class 'sage.combinat.words.word.FiniteWord_list'>

        Creation of a word from a concatenation of words::

            sage: W = Words()
            sage: w = W() * W('a')
            sage: Z = Words('ab')
            sage: Z(w)
            word: a

        Creation of a word path from a FiniteWord_iter::

            sage: w = words.FibonacciWord()
            sage: f = w[:100]
            sage: P = WordPaths([0,1,2,3])
            sage: p = P(f); p
            Path: 0100101001001010010100100101001001010010...
            sage: p.length()
            100

        Creation of a word path from a FiniteWord_callable::

            sage: g = Word(lambda n:n%2, length = 100)
            sage: P = WordPaths([0,1,2,3])
            sage: p = P(g); p
            Path: 0101010101010101010101010101010101010101...
            sage: p.length()
            100

        Creation of a word from a pickled function::

            sage: f = lambda n : n % 10
            sage: from sage.misc.fpickle import pickle_function
            sage: s = pickle_function(f)
            sage: Word(s, datatype='pickled_function')
            word: 0123456789012345678901234567890123456789...

        """
        from sage.combinat.words.abstract_word import Word_class
        from sage.combinat.words.word_infinite_datatypes import WordDatatype_callable, WordDatatype_iter
        from sage.combinat.words.word_datatypes import WordDatatype
        if isinstance(data, Word_class):
            ####################
            # If `data` is already a word and if its parent is self,
            # then return `data` (no matter what the parameter length,
            # datatype and length are).
            ###########################
            if data.parent() is self:
                return data
            ###########################
            # Otherwise, if self is not the parent of `data`, then we
            # try to recover the data, the length and the datatype of the
            # input `data`
            ###########################
            if isinstance(data, WordDatatype_callable):
                from sage.combinat.words.finite_word import CallableFromListOfWords
                if isinstance(data._func, CallableFromListOfWords):
                    # The following line is important because, in this case,
                    # data._func is also a tuple (indeed
                    # CallableFromListOfWords inherits from tuple)
                    datatype = "callable"
                if length is None:
                    length = data._len
                data = data._func
            elif isinstance(data, WordDatatype_iter):
                if length is None:
                    length = data._len
                data = iter(data)
            elif isinstance(data, WordDatatype):
                data = data._data
            else:
                raise TypeError, "Any instance of Word_class must be an instance of WordDatatype."

        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"
            else:
                raise ValueError, "Cannot guess a datatype from data (=%s); please specify one" % data
        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",
                                  "pickled_function"):
                raise ValueError, "Unknown datatype (=%s)" % datatype

        # If `data` is a pickled_function, restore the function
        if datatype == 'pickled_function':
            from sage.misc.fpickle import unpickle_function
            data = unpickle_function(data)
            datatype = 'callable'

        # Construct the word class and keywords
        if datatype in ('list', 'str', 'tuple'):
            cls_str = 'FiniteWord_%s' % datatype
            kwds = dict(parent=self, data=data)
        elif datatype == 'callable':
            if length in (None, Infinity, 'infinite'):
                cls_str = 'InfiniteWord_callable'
            else:
                cls_str = 'FiniteWord_callable'
            if caching:
                cls_str += '_with_caching'
            kwds = dict(parent=self, callable=data, length=length)
        elif datatype == 'iter':
            if length in (None, Infinity, 'infinite'):
                cls_str = 'InfiniteWord_iter'
            elif length == 'finite':
                cls_str = 'FiniteWord_iter'
            elif length == 'unknown':
                cls_str = 'Word_iter'
            elif length in ZZ and length >= 0:
                cls_str = 'FiniteWord_iter'
            else:
                raise ValueError, "not a correct value for length (%s)" % length
            if caching:
                cls_str += '_with_caching'
            kwds = dict(parent=self, iter=data, length=length)
        else:
            raise ValueError, "Not known datatype"

        wordclass = self._element_classes
        cls = wordclass[cls_str]
        w = cls(**kwds)
        return w

    def _check(self, w, length=40):
        r"""
        Check that the first length elements are actually in the alphabet.

        NOTE:

        EXAMPLES::

            sage: from sage.combinat.words.words import Words_over_Alphabet
            sage: W = Words_over_Alphabet(['a','b','c'])
            sage: W._check('abcabc') is None
            True
            sage: W._check('abcabcd')
            Traceback (most recent call last):
            ...
            ValueError: d not in alphabet!
            sage: W._check('abcabc'*10+'z') is None
            True
            sage: W._check('abcabc'*10+'z', length=80)
            Traceback (most recent call last):
            ...
            ValueError: z not in alphabet!
        """
        for a in itertools.islice(w, length):
            if a not in self._alphabet:
                raise ValueError, "%s not in alphabet!" % a

    def _repr_(self):
        """
        EXAMPLES::

            sage: from sage.combinat.words.words import Words_all
            sage: Words_all()._repr_()
            'Words'
        """
        return 'Words'

    def __contains__(self, x):
        """
        Returns True if x is contained in self.

        EXAMPLES::

            sage: from sage.combinat.words.words import Words_all
            sage: 2 in Words_all()
            False
            sage: [1,2] in Words_all()
            False
            sage: Words('ab')('abba') in Words_all()
            True
        """
        from sage.combinat.words.abstract_word import Word_class
        return isinstance(x, Word_class)

    def __eq__(self, other):
        r"""
        Returns True if self is equal to other and False otherwise.
        
        EXAMPLES::

            sage: Words('ab') == Words()
            False
            sage: Words() == Words('ab')
            False
            sage: Words('ab') == Words('ab')
            True
            sage: Words('ab') == Words('ba')
            False
            sage: Words('ab') == Words('abc')
            False
            sage: Words('abc') == Words('ab')
            False

        ::

            sage: WordPaths('abcd') == Words('abcd')
            True
            sage: Words('abcd') == WordPaths('abcd')
            True
            sage: Words('bacd') == WordPaths('abcd')
            False
            sage: WordPaths('bacd') == WordPaths('abcd')
            False
        """
        if isinstance(other, Words_all):
            return self.alphabet() == other.alphabet()
        else:
            return NotImplemented

    def __ne__(self, other):
        r"""
        Returns True if self is not equal to other and False otherwise.
        
        TESTS::

            sage: Words('ab') != Words('ab')
            False
            sage: Words('ab') != Words('abc')
            True
            sage: Words('abc') != Words('ab')
            True
        
        ::

            sage: WordPaths('abcd') != Words('abcd')
            False
            sage: Words('abcd') != WordPaths('abcd')
            False

        ::
            
            Words('ab') != 2
            True
        """
        if isinstance(other, Words_all):
            return not self.__eq__(other)
        else:
            return NotImplemented

    _alphabet = Set_PythonType(object)

    def alphabet(self):
        r"""
        EXAMPLES::

            sage: from sage.combinat.words.words import Words_over_Alphabet
            sage: W = Words_over_Alphabet([1,2,3])
            sage: W.alphabet()
            [1, 2, 3]
            sage: from sage.combinat.words.alphabet import build_alphabet
            sage: W = Words_over_Alphabet(build_alphabet('ab'))
            sage: W.alphabet()
            {'a', 'b'}
        """
        return self._alphabet

    def size_of_alphabet(self):
        r"""
        Returns the size of the alphabet.
        
        EXAMPLES::

            sage: Words().size_of_alphabet()
            +Infinity
        """
        return Infinity

    cmp_letters = cmp

    def has_letter(self, letter):
        r"""
        Returns True if the alphabet of self contains the given letter.

        INPUT:

        -  ``letter`` - a letter

        EXAMPLES::

            sage: W = Words()
            sage: W.has_letter('a')
            True
            sage: W.has_letter(1)
            True
            sage: W.has_letter({})
            True
            sage: W.has_letter([])
            True
            sage: W.has_letter(range(5))
            True
            sage: W.has_letter(Permutation([]))
            True

            sage: from sage.combinat.words.words import Words_over_Alphabet
            sage: W = Words_over_Alphabet(['a','b','c'])
            sage: W.has_letter('a')
            True
            sage: W.has_letter('d')
            False
            sage: W.has_letter(8)
            False
        """
        return letter in self._alphabet