def node_to_word(self, state=0): r""" Returns the word obtained by reading the edge labels from 0 to ``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) sage: t.node_to_word(10) word: abcba sage: t.node_to_word(7) word: abcb """ if state == 0: return Words(self._alphabet)() # We first invert the transition function tf_inv = {b: a for a, b in iteritems(self._transition_function)} # Starting from the active state, # read labels along the unique path to the root. (u, letter) = tf_inv[state] w = letter s = u while s != 0: (u, letter) = tf_inv[s] w = letter * w s = u return w
def process_letter(self, letter): r""" Modify ``self`` to produce 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: 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): ... ValueError: d not in alphabet! """ # Make certain that letter is a word containing one letter. letter = Words(self._alphabet)([letter]) self._process_letter(letter)
def __init__(self, R, names): r""" Initialize ``self``. EXAMPLES:: sage: F = ShuffleAlgebra(QQ, 'xyz'); F Shuffle Algebra on 3 generators ['x', 'y', 'z'] over Rational Field sage: TestSuite(F).run() TESTS:: sage: ShuffleAlgebra(24, 'toto') Traceback (most recent call last): ... TypeError: argument R must be a ring """ if R not in Rings(): raise TypeError("argument R must be a ring") self._alphabet = names self.__ngens = self._alphabet.cardinality() CombinatorialFreeModule.__init__(self, R, Words(names, infinite=False), latex_prefix="", category=(AlgebrasWithBasis(R), CommutativeAlgebras(R), CoalgebrasWithBasis(R)))
def from_finite_word(self, w): r""" Return the unique ordered set partition of `\{1, 2, \ldots, n\}` corresponding to a word `w` of length `n`. .. SEEALSO:: :meth:`Word.to_ordered_set_partition` EXAMPLES:: sage: A = OrderedSetPartitions().from_finite_word('abcabcabd'); A [{1, 4, 7}, {2, 5, 8}, {3, 6}, {9}] sage: B = OrderedSetPartitions().from_finite_word([1,2,3,1,2,3,1,2,4]) sage: A == B True """ # TODO: fix this if statement. # In fact, what we need is for the underlying alphabet to be sortable. if isinstance(w, (list, tuple, str, FiniteWord_class)): return self.element_class(self, Words()(w).to_ordered_set_partition()) else: raise ValueError( "Something is wrong: `from_finite_word` expects an object of type list/tuple/str/Word representing a finite word, received {}." .format(str(w)))
def to_word_by_row(self): """ Returns a word obtained from a row reading of the skew tableau. EXAMPLES:: sage: s = SkewTableau([[None,1],[2,3]]) sage: s.pp() . 1 2 3 sage: s.to_word_by_row() word: 231 sage: s = SkewTableau([[None, 2, 4], [None, 3], [1]]) sage: s.pp() . 2 4 . 3 1 sage: s.to_word_by_row() word: 1324 """ word = [] for row in self: word = row + word return Words("positive integers")([i for i in word if i is not None])
def _gen_names(elts): r""" Used to find a name for a generator when rings are created using the ``__getitem__`` syntax, e.g. ``ZZ['x']``, ``ZZ[sqrt(2)]``. EXAMPLES:: sage: from sage.categories.rings import _gen_names sage: list(_gen_names([sqrt(5)])) ['sqrt5'] sage: list(_gen_names([sqrt(-17), 2^(1/3)])) ['a', 'b'] sage: list(_gen_names((1..27)))[-1] 'aa' """ import re from sage.structure.category_object import certify_names from sage.combinat.words.words import Words it = iter(Words("abcdefghijklmnopqrstuvwxyz", infinite=False)) next(it) # skip empty word for x in elts: name = str(x) m = re.match(r'^sqrt\((\d+)\)$', name) if m: name = "sqrt%s" % m.groups()[0] try: certify_names([name]) except ValueError: name = next(it).string_rep() yield name
def _gen_names(elts): r""" Used to find a name for a generator when rings are created using the ``__getitem__`` syntax, e.g. ``ZZ['x']``, ``ZZ[sqrt(2)]``. EXAMPLES:: sage: from sage.categories.rings import _gen_names sage: list(_gen_names([sqrt(5)])) ['sqrt5'] sage: list(_gen_names([sqrt(-17), 2^(1/3)])) ['a', 'b'] sage: list(_gen_names((1..27)))[-1] 'aa' """ from sage.symbolic.ring import is_SymbolicVariable from sage.combinat.words.words import Words it = iter(Words("abcdefghijklmnopqrstuvwxyz")) it.next() # skip empty word for x in elts: name = str(x) m = re.match('^sqrt\((\d+)\)$', name) if m: name = "sqrt%s" % m.groups()[0] try: _certify_names([name]) except ValueError as msg: name = it.next().string_rep() yield name
def __init__(self, R, n, names): """ Initialize ``self``. EXAMPLES:: sage: Z.<x,y,z> = algebras.FreeZinbiel(QQ) sage: TestSuite(Z).run() TESTS:: sage: Z.<x,y,z> = algebras.FreeZinbiel(5) Traceback (most recent call last): ... TypeError: argument R must be a ring """ if R not in Rings: raise TypeError("argument R must be a ring") indices = Words(Alphabet(n, names=names)) cat = MagmaticAlgebras(R).WithBasis().Graded() self._n = n CombinatorialFreeModule.__init__(self, R, indices, prefix='Z', category=cat) self._assign_names(names)
def __init__(self, R, names, prefix): r""" Initialize ``self``. EXAMPLES:: sage: F = ShuffleAlgebra(QQ, 'xyz'); F Shuffle Algebra on 3 generators ['x', 'y', 'z'] over Rational Field sage: TestSuite(F).run() # long time TESTS:: sage: ShuffleAlgebra(24, 'toto') Traceback (most recent call last): ... TypeError: argument R must be a ring sage: F = ShuffleAlgebra(QQ, 'xyz', prefix='f'); F Shuffle Algebra on 3 generators ['x', 'y', 'z'] over Rational Field sage: F.gens() Family (f[word: x], f[word: y], f[word: z]) """ if R not in Rings(): raise TypeError("argument R must be a ring") self._alphabet = names self.__ngens = self._alphabet.cardinality() cat = GradedHopfAlgebrasWithBasis(R).Commutative().Connected() CombinatorialFreeModule.__init__(self, R, Words(names, infinite=False), latex_prefix="", prefix=prefix, category=cat)
def words_of_length_iterator(self, length): r""" Return an iterator over words of given length. INPUT: - ``length`` -- integer EXAMPLES:: sage: from slabbe.language import Language sage: F = Language(alphabet=['a', 'b']) sage: it = F.words_of_length_iterator(2) sage: list(it) [word: aa, word: ab, word: ba, word: bb] """ W = Words(self._alphabet) return W.iterate_by_length(length)
def __init__(self, R, alphabet = ("a", "b", "c")): """ EXAMPLES:: sage: A = AlgebrasWithBasis(QQ).example(); A An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field sage: TestSuite(A).run() """ self._alphabet = alphabet CombinatorialFreeModule.__init__(self, R, Words(alphabet), category = AlgebrasWithBasis(R))
def algebra_generators(self): r""" Return the generators of this algebra. EXAMPLES:: sage: A = ShuffleAlgebra(ZZ,'fgh'); A Shuffle Algebra on 3 generators ['f', 'g', 'h'] over Integer Ring sage: A.algebra_generators() Family (B[word: f], B[word: g], B[word: h]) """ Words = self.basis().keys() return Family([self.monomial(Words(a)) for a in self._alphabet])
def __init__(self, R, n, names, prefix): """ Initialize ``self``. EXAMPLES:: sage: Z.<x,y,z> = algebras.FreeZinbiel(QQ) sage: TestSuite(Z).run() sage: Z = algebras.FreeZinbiel(QQ, ZZ) sage: G = Z.algebra_generators() sage: TestSuite(Z).run(elements=[Z.an_element(), G[1], G[1]*G[2]*G[0]]) TESTS:: sage: Z.<x,y,z> = algebras.FreeZinbiel(5) Traceback (most recent call last): ... TypeError: argument R must be a ring sage: algebras.FreeZinbiel(QQ, ['x', 'y'], prefix='f') Free Zinbiel algebra on generators (f[x], f[y]) over Rational Field """ if R not in Rings(): raise TypeError("argument R must be a ring") if names is None: indices = Words(Alphabet(n), infinite=False) self._n = None else: indices = Words(Alphabet(n, names=names), infinite=False) self._n = n cat = MagmaticAlgebras(R).WithBasis().Graded() CombinatorialFreeModule.__init__(self, R, indices, prefix=prefix, category=cat) if self._n is not None: self._assign_names(names)
def algebra_generators(self): r""" Returns the generators of this algebra, as per :meth:`Algebras.ParentMethods.algebra_generators`. EXAMPLES:: sage: A = AlgebrasWithBasis(QQ).example(); A An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field sage: A.algebra_generators() Family (B[word: a], B[word: b], B[word: c]) """ Words = self.basis().keys() return Family( [self.monomial(Words(a)) for a in self._alphabet] )
def __init__(self, R, names): """ Initialize ``self``. EXAMPLES:: sage: D = ShuffleAlgebra(QQ, 'ab').dual_pbw_basis() sage: TestSuite(D).run() """ self._alphabet = names self._alg = ShuffleAlgebra(R, names) CombinatorialFreeModule.__init__(self, R, Words(names), prefix='S', category=(AlgebrasWithBasis(R), CommutativeAlgebras(R), CoalgebrasWithBasis(R)))
def __classcall_private__(cls, parts=None, from_word=None): """ Create a set partition from ``parts`` with the appropriate parent. EXAMPLES:: sage: s = OrderedSetPartition([[1,3],[2,4]]); s [{1, 3}, {2, 4}] sage: s.parent() Ordered set partitions of {1, 2, 3, 4} sage: t = OrderedSetPartition([[2,4],[1,3]]); t [{2, 4}, {1, 3}] sage: s != t True sage: OrderedSetPartition() [] sage: OrderedSetPartition([]) [] sage: OrderedSetPartition('') [] sage: OrderedSetPartition('bdab') == OrderedSetPartition(from_word='bdab') True sage: OrderedSetPartition('bdab') == OrderedSetPartition(Word('bdab')) True """ if parts is None and from_word is None: P = OrderedSetPartitions([]) return P.element_class(P, []) if from_word: return OrderedSetPartitions().from_finite_word(Words()(from_word)) # if `parts` looks like a sequence of "letters" then treat it like a word. if parts in Words() or (len(parts) > 0 and (parts[0] in ZZ or isinstance(parts[0], str))): return OrderedSetPartitions().from_finite_word(Words()(parts)) else: P = OrderedSetPartitions( reduce(lambda x, y: x.union(y), map(Set, parts), Set([]))) return P.element_class(P, parts)
def __init__(self, R, names): """ Initialize ``self``. EXAMPLES:: sage: D = ShuffleAlgebra(QQ, 'ab').dual_pbw_basis() sage: TestSuite(D).run() # long time """ self._alphabet = names self._alg = ShuffleAlgebra(R, names) cat = GradedHopfAlgebrasWithBasis(R).Commutative().Connected() CombinatorialFreeModule.__init__(self, R, Words(names), prefix='S', category=cat)
def to_word_by_row(self): """ Returns a word obtained from a row reading of the ribbon. EXAMPLES:: sage: Ribbon([[1],[2,3]]).to_word_by_row() word: 231 sage: Ribbon([[2, 4], [3], [1]]).to_word_by_row() word: 1324 """ word = [] for row in self: word = row + word return Words(alphabet="positive integers")(word)
def __init__(self, w=ZZ_1, r=ZZ_2, h1=ZZ_1, h2=ZZ_1): from sage.combinat.words.words import Words field = Sequence([w, r, h1, h2]).universe() if not field.is_field(): field = field.fraction_field() self._w = field(w) self._r = field(r) self._h1 = field(h1) self._h2 = field(h2) self._words = Words('LR', finite=True, infinite=False) self._wL = self._words('L') self._wR = self._words('R') base_label = self.polygon_labels()._cartesian_product_of_elements( (self._words(''), 0)) Surface.__init__(self, field, base_label, finite=False)
def to_packed_word(self): r""" Return the packed word on alphabet `\{1,2,3,\ldots\}` corresponding to ``self``. A *packed word* on alphabet `\{1,2,3,\ldots\}` is any word whose maximum letter is the same as its total number of distinct letters. Let `P` be an ordered set partition of a set `X`. The corresponding packed word `w_1 w_2 \cdots w_n` is constructed by having letter `w_i = j` if the `i`-th smallest entry in `X` occurs in the `j`-th block of `P`. .. SEEALSO:: :meth:`Word.to_ordered_set_partition` .. WARNING:: This assumes there is a total order on the underlying set (``self._base_set``). EXAMPLES:: sage: S = OrderedSetPartitions() sage: x = S([[3,5], [2], [1,4,6]]) sage: x.to_packed_word() word: 321313 sage: x = S([['a', 'c', 'e'], ['b', 'd']]) sage: x.to_packed_word() word: 12121 """ X = sorted(self._base_set) out = {} for i in range(len(self)): for letter in self[i]: out[letter] = i return Words()([out[letter] + 1 for letter in X])
def __init__(self, parent=None): r""" Constructor. See documentation of WordDatatype_Kolakoski for more details. EXAMPLES:: sage: from slabbe import KolakoskiWord sage: K = KolakoskiWord() sage: K word: 1221121221221121122121121221121121221221... TESTS: Pickle is supported:: sage: K = KolakoskiWord() sage: loads(dumps(K)) word: 1221121221221121122121121221121121221221... """ if parent is None: from sage.combinat.words.words import Words parent = Words([1, 2]) WordDatatype_Kolakoski.__init__(self, parent)
def Kautz(self, k, D, vertices = 'strings'): r""" Returns the Kautz digraph of degree `d` and diameter `D`. The Kautz digraph has been defined in [Kautz68]_. The Kautz digraph of degree `d` and diameter `D` has `d^{D-1}(d+1)` vertices. This digraph is build upon a set of vertices equal to the set of words of length `D` from an alphabet of `d+1` letters such that consecutive letters are differents. There is an arc from vertex `u` to vertex `v` if `v` can be obtained from `u` by removing the leftmost letter and adding a new letter, distinct from the rightmost letter of `u`, at the right end. The Kautz digraph of degree `d` and diameter `D` is isomorphic to the digraph of Imase and Itoh [II83]_ of degree `d` and order `d^{D-1}(d+1)`. See also the :wikipedia:`Wikipedia article on Kautz Graphs <Kautz_graph>`. INPUTS: - ``k`` -- Two possibilities for this parameter : - An integer equal to the degree of the digraph to be produced, that is the cardinality minus one of the alphabet to use. - An iterable object to be used as the set of letters. The degree of the resulting digraph is the cardinality of the set of letters minus one. - ``D`` -- An integer equal to the diameter of the digraph, and also to the length of a vertex label when ``vertices == 'strings'``. - ``vertices`` -- 'strings' (default) or 'integers', specifying whether the vertices are words build upon an alphabet or integers. EXAMPLES:: sage: K = digraphs.Kautz(2, 3) sage: K.is_isomorphic(digraphs.ImaseItoh(12, 2), certify = True) (True, {'010': 0, '012': 1, '020': 3, '021': 2, '101': 11, '102': 10, '120': 9, '121': 8, '201': 5, '202': 4, '210': 6, '212': 7}) sage: K = digraphs.Kautz([1,'a','B'], 2) sage: K.edges() [('1B', 'B1', '1'), ('1B', 'Ba', 'a'), ('1a', 'a1', '1'), ('1a', 'aB', 'B'), ('B1', '1B', 'B'), ('B1', '1a', 'a'), ('Ba', 'a1', '1'), ('Ba', 'aB', 'B'), ('a1', '1B', 'B'), ('a1', '1a', 'a'), ('aB', 'B1', '1'), ('aB', 'Ba', 'a')] sage: K = digraphs.Kautz([1,'aA','BB'], 2) sage: K.edges() [('1,BB', 'BB,1', '1'), ('1,BB', 'BB,aA', 'aA'), ('1,aA', 'aA,1', '1'), ('1,aA', 'aA,BB', 'BB'), ('BB,1', '1,BB', 'BB'), ('BB,1', '1,aA', 'aA'), ('BB,aA', 'aA,1', '1'), ('BB,aA', 'aA,BB', 'BB'), ('aA,1', '1,BB', 'BB'), ('aA,1', '1,aA', 'aA'), ('aA,BB', 'BB,1', '1'), ('aA,BB', 'BB,aA', 'aA')] TESTS: An exception is raised when the degree is less than one:: sage: G = digraphs.Kautz(0, 2) Traceback (most recent call last): ... ValueError: Kautz digraphs are defined for degree at least one. sage: G = digraphs.Kautz(['a'], 2) Traceback (most recent call last): ... ValueError: Kautz digraphs are defined for degree at least one. An exception is raised when the diameter of the graph is less than one:: sage: G = digraphs.Kautz(2, 0) Traceback (most recent call last): ... ValueError: Kautz digraphs are defined for diameter at least one. REFERENCE: .. [Kautz68] W. H. Kautz. Bounds on directed (d, k) graphs. Theory of cellular logic networks and machines, AFCRL-68-0668, SRI Project 7258, Final Rep., pp. 20-28, 1968. """ if D < 1: raise ValueError("Kautz digraphs are defined for diameter at least one.") from sage.combinat.words.words import Words from sage.rings.integer import Integer my_alphabet = Words([str(i) for i in range(k+1)] if isinstance(k, Integer) else k, 1) if my_alphabet.size_of_alphabet() < 2: raise ValueError("Kautz digraphs are defined for degree at least one.") if vertices == 'strings': # We start building the set of vertices V = [i for i in my_alphabet] for i in range(D-1): VV = [] for w in V: VV += [w*a for a in my_alphabet if not w.has_suffix(a) ] V = VV # We now build the set of arcs G = DiGraph() for u in V: for a in my_alphabet: if not u.has_suffix(a): G.add_edge(u.string_rep(), (u[1:]*a).string_rep(), a.string_rep()) else: d = my_alphabet.size_of_alphabet()-1 G = digraphs.ImaseItoh( (d+1)*(d**(D-1)), d) G.name( "Kautz digraph (k=%s, D=%s)"%(k,D) ) return G
def Kautz(self, k, D, vertices='strings'): r""" Returns the Kautz digraph of degree `d` and diameter `D`. The Kautz digraph has been defined in [Kautz68]_. The Kautz digraph of degree `d` and diameter `D` has `d^{D-1}(d+1)` vertices. This digraph is build upon a set of vertices equal to the set of words of length `D` from an alphabet of `d+1` letters such that consecutive letters are differents. There is an arc from vertex `u` to vertex `v` if `v` can be obtained from `u` by removing the leftmost letter and adding a new letter, distinct from the rightmost letter of `u`, at the right end. The Kautz digraph of degree `d` and diameter `D` is isomorphic to the digraph of Imase and Itoh [II83]_ of degree `d` and order `d^{D-1}(d+1)`. See also the :wikipedia:`Wikipedia article on Kautz Graphs <Kautz_graph>`. INPUTS: - ``k`` -- Two possibilities for this parameter : - An integer equal to the degree of the digraph to be produced, that is the cardinality minus one of the alphabet to use. - An iterable object to be used as the set of letters. The degree of the resulting digraph is the cardinality of the set of letters minus one. - ``D`` -- An integer equal to the diameter of the digraph, and also to the length of a vertex label when ``vertices == 'strings'``. - ``vertices`` -- 'strings' (default) or 'integers', specifying whether the vertices are words build upon an alphabet or integers. EXAMPLES:: sage: K = digraphs.Kautz(2, 3) sage: K.is_isomorphic(digraphs.ImaseItoh(12, 2), certify = True) (True, {'010': 0, '012': 1, '020': 3, '021': 2, '101': 11, '102': 10, '120': 9, '121': 8, '201': 5, '202': 4, '210': 6, '212': 7}) sage: K = digraphs.Kautz([1,'a','B'], 2) sage: K.edges() [('1B', 'B1', '1'), ('1B', 'Ba', 'a'), ('1a', 'a1', '1'), ('1a', 'aB', 'B'), ('B1', '1B', 'B'), ('B1', '1a', 'a'), ('Ba', 'a1', '1'), ('Ba', 'aB', 'B'), ('a1', '1B', 'B'), ('a1', '1a', 'a'), ('aB', 'B1', '1'), ('aB', 'Ba', 'a')] sage: K = digraphs.Kautz([1,'aA','BB'], 2) sage: K.edges() [('1,BB', 'BB,1', '1'), ('1,BB', 'BB,aA', 'aA'), ('1,aA', 'aA,1', '1'), ('1,aA', 'aA,BB', 'BB'), ('BB,1', '1,BB', 'BB'), ('BB,1', '1,aA', 'aA'), ('BB,aA', 'aA,1', '1'), ('BB,aA', 'aA,BB', 'BB'), ('aA,1', '1,BB', 'BB'), ('aA,1', '1,aA', 'aA'), ('aA,BB', 'BB,1', '1'), ('aA,BB', 'BB,aA', 'aA')] TESTS: An exception is raised when the degree is less than one:: sage: G = digraphs.Kautz(0, 2) Traceback (most recent call last): ... ValueError: Kautz digraphs are defined for degree at least one. sage: G = digraphs.Kautz(['a'], 2) Traceback (most recent call last): ... ValueError: Kautz digraphs are defined for degree at least one. An exception is raised when the diameter of the graph is less than one:: sage: G = digraphs.Kautz(2, 0) Traceback (most recent call last): ... ValueError: Kautz digraphs are defined for diameter at least one. REFERENCE: .. [Kautz68] W. H. Kautz. Bounds on directed (d, k) graphs. Theory of cellular logic networks and machines, AFCRL-68-0668, SRI Project 7258, Final Rep., pp. 20-28, 1968. """ if D < 1: raise ValueError( "Kautz digraphs are defined for diameter at least one.") from sage.combinat.words.words import Words from sage.rings.integer import Integer my_alphabet = Words( [str(i) for i in range(k + 1)] if isinstance(k, Integer) else k, 1) if my_alphabet.size_of_alphabet() < 2: raise ValueError( "Kautz digraphs are defined for degree at least one.") if vertices == 'strings': # We start building the set of vertices V = [i for i in my_alphabet] for i in range(D - 1): VV = [] for w in V: VV += [w * a for a in my_alphabet if not w.has_suffix(a)] V = VV # We now build the set of arcs G = DiGraph() for u in V: for a in my_alphabet: if not u.has_suffix(a): G.add_edge(u.string_rep(), (u[1:] * a).string_rep(), a.string_rep()) else: d = my_alphabet.size_of_alphabet() - 1 G = digraphs.ImaseItoh((d + 1) * (d**(D - 1)), d) G.name("Kautz digraph (k=%s, D=%s)" % (k, D)) return G
def DeBruijn(self, k, n, vertices = 'strings'): r""" Returns the De Bruijn digraph with parameters `k,n`. The De Bruijn digraph with parameters `k,n` is built upon a set of vertices equal to the set of words of length `n` from a dictionary of `k` letters. In this digraph, there is an arc `w_1w_2` if `w_2` can be obtained from `w_1` by removing the leftmost letter and adding a new letter at its right end. For more information, see the :wikipedia:`Wikipedia article on De Bruijn graph <De_Bruijn_graph>`. INPUT: - ``k`` -- Two possibilities for this parameter : - An integer equal to the cardinality of the alphabet to use, that is the degree of the digraph to be produced. - An iterable object to be used as the set of letters. The degree of the resulting digraph is the cardinality of the set of letters. - ``n`` -- An integer equal to the length of words in the De Bruijn digraph when ``vertices == 'strings'``, and also to the diameter of the digraph. - ``vertices`` -- 'strings' (default) or 'integers', specifying whether the vertices are words build upon an alphabet or integers. EXAMPLES:: sage: db=digraphs.DeBruijn(2,2); db De Bruijn digraph (k=2, n=2): Looped digraph on 4 vertices sage: db.order() 4 sage: db.size() 8 TESTS:: sage: digraphs.DeBruijn(5,0) De Bruijn digraph (k=5, n=0): Looped multi-digraph on 1 vertex sage: digraphs.DeBruijn(0,0) De Bruijn digraph (k=0, n=0): Looped multi-digraph on 0 vertices """ from sage.combinat.words.words import Words from sage.rings.integer import Integer W = Words(range(k) if isinstance(k, Integer) else k, n) A = Words(range(k) if isinstance(k, Integer) else k, 1) g = DiGraph(loops=True) if vertices == 'strings': if n == 0 : g.allow_multiple_edges(True) v = W[0] for a in A: g.add_edge(v.string_rep(), v.string_rep(), a.string_rep()) else: for w in W: ww = w[1:] for a in A: g.add_edge(w.string_rep(), (ww*a).string_rep(), a.string_rep()) else: d = W.size_of_alphabet() g = digraphs.GeneralizedDeBruijn(d**n, d) g.name( "De Bruijn digraph (k=%s, n=%s)"%(k,n) ) return g
def DeBruijn(self,k,n): r""" Returns the De Bruijn diraph with parameters `k,n`. The De Bruijn digraph with parameters `k,n` is built upon a set of vertices equal to the set of words of length `n` from a dictionary of `k` letters. In this digraph, there is an arc `w_1w_2` if `w_2` can be obtained from `w_1` by removing the leftmost letter and adding a new letter at its right end. For more information, see the `Wikipedia article on De Bruijn graph <http://en.wikipedia.org/wiki/De_Bruijn_graph>`_. INPUT: - ``k`` -- Two possibilities for this parameter : - an integer equal to the cardinality of the alphabet to use. - An iterable object to be used as the set of letters - ``n`` -- An integer equal to the length of words in the De Bruijn digraph. EXAMPLES:: sage: db=digraphs.DeBruijn(2,2); db De Bruijn digraph (k=2, n=2): Looped digraph on 4 vertices sage: db.order() 4 sage: db.size() 8 TESTS:: sage: digraphs.DeBruijn(5,0) De Bruijn digraph (k=5, n=0): Looped multi-digraph on 1 vertex sage: digraphs.DeBruijn(0,0) De Bruijn digraph (k=0, n=0): Looped multi-digraph on 0 vertices """ from sage.combinat.words.words import Words from sage.rings.integer import Integer W = Words(range(k) if isinstance(k, Integer) else k, n) A = Words(range(k) if isinstance(k, Integer) else k, 1) g = DiGraph(loops=True) if n == 0 : g.allow_multiple_edges(True) v = W[0] for a in A: g.add_edge(v.string_rep(), v.string_rep(), a.string_rep()) else: for w in W: ww = w[1:] for a in A: g.add_edge(w.string_rep(), (ww*a).string_rep(), a.string_rep()) g.name( "De Bruijn digraph (k=%s, n=%s)"%(k,n) ) return g
def DeBruijn(self, k, n, vertices='strings'): r""" Returns the De Bruijn digraph with parameters `k,n`. The De Bruijn digraph with parameters `k,n` is built upon a set of vertices equal to the set of words of length `n` from a dictionary of `k` letters. In this digraph, there is an arc `w_1w_2` if `w_2` can be obtained from `w_1` by removing the leftmost letter and adding a new letter at its right end. For more information, see the :wikipedia:`Wikipedia article on De Bruijn graph <De_Bruijn_graph>`. INPUT: - ``k`` -- Two possibilities for this parameter : - An integer equal to the cardinality of the alphabet to use, that is the degree of the digraph to be produced. - An iterable object to be used as the set of letters. The degree of the resulting digraph is the cardinality of the set of letters. - ``n`` -- An integer equal to the length of words in the De Bruijn digraph when ``vertices == 'strings'``, and also to the diameter of the digraph. - ``vertices`` -- 'strings' (default) or 'integers', specifying whether the vertices are words build upon an alphabet or integers. EXAMPLES:: sage: db=digraphs.DeBruijn(2,2); db De Bruijn digraph (k=2, n=2): Looped digraph on 4 vertices sage: db.order() 4 sage: db.size() 8 TESTS:: sage: digraphs.DeBruijn(5,0) De Bruijn digraph (k=5, n=0): Looped multi-digraph on 1 vertex sage: digraphs.DeBruijn(0,0) De Bruijn digraph (k=0, n=0): Looped multi-digraph on 0 vertices """ from sage.combinat.words.words import Words from sage.rings.integer import Integer W = Words(range(k) if isinstance(k, Integer) else k, n) A = Words(range(k) if isinstance(k, Integer) else k, 1) g = DiGraph(loops=True) if vertices == 'strings': if n == 0: g.allow_multiple_edges(True) v = W[0] for a in A: g.add_edge(v.string_rep(), v.string_rep(), a.string_rep()) else: for w in W: ww = w[1:] for a in A: g.add_edge(w.string_rep(), (ww * a).string_rep(), a.string_rep()) else: d = W.size_of_alphabet() g = digraphs.GeneralizedDeBruijn(d**n, d) g.name("De Bruijn digraph (k=%s, n=%s)" % (k, n)) return g
def Subwords(w, k=None, element_constructor=None): """ Return the set of subwords of ``w``. INPUT: - ``w`` -- a word (can be a list, a string, a tuple or a word) - ``k`` -- an optional integer to specify the length of subwords - ``element_constructor`` -- an optional function that will be used to build the subwords EXAMPLES:: sage: S = Subwords(['a','b','c']); S Subwords of ['a', 'b', 'c'] sage: S.first() [] sage: S.last() ['a', 'b', 'c'] sage: S.list() [[], ['a'], ['b'], ['c'], ['a', 'b'], ['a', 'c'], ['b', 'c'], ['a', 'b', 'c']] The same example using string, tuple or a word:: sage: S = Subwords('abc'); S Subwords of 'abc' sage: S.list() ['', 'a', 'b', 'c', 'ab', 'ac', 'bc', 'abc'] sage: S = Subwords((1,2,3)); S Subwords of (1, 2, 3) sage: S.list() [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)] sage: w = Word([1,2,3]) sage: S = Subwords(w); S Subwords of word: 123 sage: S.list() [word: , word: 1, word: 2, word: 3, word: 12, word: 13, word: 23, word: 123] Using word with specified length:: sage: S = Subwords(['a','b','c'], 2); S Subwords of ['a', 'b', 'c'] of length 2 sage: S.list() [['a', 'b'], ['a', 'c'], ['b', 'c']] An example that uses the ``element_constructor`` argument:: sage: p = Permutation([3,2,1]) sage: Subwords(p, element_constructor=tuple).list() [(), (3,), (2,), (1,), (3, 2), (3, 1), (2, 1), (3, 2, 1)] sage: Subwords(p, 2, element_constructor=tuple).list() [(3, 2), (3, 1), (2, 1)] """ if element_constructor is None: datatype = type(w) # 'datatype' is the type of w if datatype is list or datatype is tuple: element_constructor = datatype elif datatype is str: element_constructor = _stringification else: from sage.combinat.words.words import Words try: alphabet = w.parent().alphabet() element_constructor = Words(alphabet) except AttributeError: element_constructor = list if k is None: return Subwords_w(w, element_constructor) if not isinstance(k, (int, Integer)): raise ValueError("k should be an integer") if k < 0 or k > len(w): return FiniteEnumeratedSet([]) return Subwords_wk(w, k, element_constructor)