class LyndonWords_nk(UniqueRepresentation, Parent): r""" Lyndon words of fixed length `k` over the alphabet `\{1, 2, \ldots, n\}`. INPUT: - ``n`` -- the size of the alphabet - ``k`` -- the length of the words EXAMPLES:: sage: L = LyndonWords(3, 4) sage: L.list() [word: 1112, word: 1113, word: 1122, word: 1123, ... word: 1333, word: 2223, word: 2233, word: 2333] """ def __init__(self, n, k): """ Initialize ``self``. TESTS:: sage: LW23 = LyndonWords(2,3); LW23 Lyndon words from an alphabet of size 2 of length 3 sage: LW23== loads(dumps(LW23)) True """ self._n = n self._k = k self._words = FiniteWords(self._n) from sage.categories.enumerated_sets import EnumeratedSets Parent.__init__(self, category=EnumeratedSets().Finite(), facade=(self._words, )) def __repr__(self): """ TESTS:: sage: repr(LyndonWords(2, 3)) 'Lyndon words from an alphabet of size 2 of length 3' """ return "Lyndon words from an alphabet of size %s of length %s" % ( self._n, self._k) def __call__(self, *args, **kwds): r""" TESTS:: sage: L = LyndonWords(3,3) sage: L([1,2,3]) word: 123 sage: L([2,3,4]) Traceback (most recent call last): ... ValueError: 4 not in alphabet! sage: L([2,1,3]) Traceback (most recent call last): ... ValueError: not a Lyndon word sage: L([1,2,2,3,3]) Traceback (most recent call last): ... ValueError: length is not k=3 Make sure that the correct length is checked (:trac:`30186`):: sage: L = LyndonWords(2, 4) sage: _ = L(L.random_element()) """ w = self._words(*args, **kwds) if kwds.get('check', True) and not w.is_lyndon(): raise ValueError("not a Lyndon word") if kwds.get('check', True) and w.length() != self._k: raise ValueError("length is not k={}".format(self._k)) return w def __contains__(self, w): """ TESTS:: sage: LW33 = LyndonWords(3,3) sage: all(lw in LW33 for lw in LW33) True """ if isinstance(w, list): w = self._words(w, check=False) return isinstance(w, FiniteWord_class) and w.length() == self._k \ and all(x in self._words.alphabet() for x in w) and w.is_lyndon() def cardinality(self): """ TESTS:: sage: [ LyndonWords(3,i).cardinality() for i in range(1, 11) ] [3, 3, 8, 18, 48, 116, 312, 810, 2184, 5880] """ if self._k == 0: return Integer(1) else: s = Integer(0) for d in divisors(self._k): s += moebius(d) * self._n**(self._k // d) return s // self._k def __iter__(self): """ TESTS:: sage: LyndonWords(3,3).list() # indirect doctest [word: 112, word: 113, word: 122, word: 123, word: 132, word: 133, word: 223, word: 233] sage: sum(1 for lw in LyndonWords(11, 6)) 295020 sage: sum(1 for lw in LyndonWords(1000, 1)) 1000 sage: sum(1 for lw in LyndonWords(1, 1000)) 0 sage: list(LyndonWords(1, 1)) [word: 1] """ W = self._words._element_classes['list'] for lw in lyndon_word_iterator(self._n, self._k): yield W(self._words, [i + 1 for i in lw])
class LyndonWords_evaluation(UniqueRepresentation, Parent): r""" The set of Lyndon words on a fixed multiset of letters. EXAMPLES:: sage: L = LyndonWords([1,2,1]) sage: L Lyndon words with evaluation [1, 2, 1] sage: L.list() [word: 1223, word: 1232, word: 1322] """ def __init__(self, e): """ TESTS:: sage: LW21 = LyndonWords([2,1]); LW21 Lyndon words with evaluation [2, 1] sage: LW21 == loads(dumps(LW21)) True """ self._e = e self._words = FiniteWords(len(e)) from sage.categories.enumerated_sets import EnumeratedSets Parent.__init__(self, category=EnumeratedSets().Finite(), facade=(self._words, )) def __repr__(self): """ TESTS:: sage: repr(LyndonWords([2,1,1])) 'Lyndon words with evaluation [2, 1, 1]' """ return "Lyndon words with evaluation %s" % self._e def __call__(self, *args, **kwds): r""" TESTS:: sage: L = LyndonWords([1,2,1]) sage: L([1,2,2,3]) word: 1223 sage: L([2,1,2,3]) Traceback (most recent call last): ... ValueError: not a Lyndon word sage: L([1,2]) Traceback (most recent call last): ... ValueError: evaluation is not [1, 2, 1] """ w = self._words(*args, **kwds) if kwds.get('check', True) and not w.is_lyndon(): raise ValueError("not a Lyndon word") if kwds.get('check', True) and w.evaluation() != self._e: raise ValueError("evaluation is not {}".format(self._e)) return w def __contains__(self, w): """ EXAMPLES:: sage: [1,2,1,2] in LyndonWords([2,2]) False sage: [1,1,2,2] in LyndonWords([2,2]) True sage: all(lw in LyndonWords([2,1,3,1]) for lw in LyndonWords([2,1,3,1])) True """ if isinstance(w, list): w = self._words(w, check=False) if isinstance(w, FiniteWord_class) and all(x in self._words.alphabet() for x in w): ev_dict = w.evaluation_dict() evaluation = [ev_dict.get(x, 0) for x in self._words.alphabet()] return evaluation == self._e and w.is_lyndon() else: return False def cardinality(self): """ Return the number of Lyndon words with the evaluation e. EXAMPLES:: sage: LyndonWords([]).cardinality() 0 sage: LyndonWords([2,2]).cardinality() 1 sage: LyndonWords([2,3,2]).cardinality() 30 Check to make sure that the count matches up with the number of Lyndon words generated:: sage: comps = [[],[2,2],[3,2,7],[4,2]] + Compositions(4).list() sage: lws = [LyndonWords(comp) for comp in comps] sage: all(lw.cardinality() == len(lw.list()) for lw in lws) True """ evaluation = self._e le = list(evaluation) if not evaluation: return Integer(0) n = sum(evaluation) return sum( moebius(j) * multinomial([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. EXAMPLES:: sage: LyndonWords([1]).list() #indirect doctest [word: 1] sage: LyndonWords([2]).list() #indirect doctest [] sage: LyndonWords([3]).list() #indirect doctest [] sage: LyndonWords([3,1]).list() #indirect doctest [word: 1112] sage: LyndonWords([2,2]).list() #indirect doctest [word: 1122] sage: LyndonWords([1,3]).list() #indirect doctest [word: 1222] sage: LyndonWords([3,3]).list() #indirect doctest [word: 111222, word: 112122, word: 112212] sage: LyndonWords([4,3]).list() #indirect doctest [word: 1111222, word: 1112122, word: 1112212, word: 1121122, word: 1121212] TESTS: Check that :trac:`12997` is fixed:: sage: LyndonWords([0,1]).list() [word: 2] sage: LyndonWords([0,2]).list() [] sage: LyndonWords([0,0,1,0,1]).list() [word: 35] """ if not self._e: return k = 0 while self._e[k] == 0: k += 1 for z in _sfc(self._e[k:], equality=True): yield self._words([i + k + 1 for i in z], check=False)