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)
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")
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