Path: blob/master/src/sage/combinat/debruijn_sequence.pyx
8817 views
# -*- coding: utf-8 -*-1r"""2De Bruijn sequences34A De Bruijn sequence is defined as the shortest cyclic sequence that5incorporates all substrings of a certain length of an alphabet.67For instance, the `2^3=8` binary strings of length 3 are all included in the8following string::910sage: DeBruijnSequences(2,3).an_element()11[0, 0, 0, 1, 0, 1, 1, 1]1213They can be obtained as a subsequence of the *cyclic* De Bruijn sequence of14parameters `k=2` and `n=3`::1516sage: seq = DeBruijnSequences(2,3).an_element()17sage: print Word(seq).string_rep()180001011119sage: shift = lambda i: [(i+j)%2**3 for j in range(3)]20sage: for i in range(2**3):21... print (Word(map(lambda (j,b): b if j in shift(i) else '*',22... enumerate(seq))).string_rep())23000*****24*001****25**010***26***101**27****011*28*****111290*****113000*****13132This sequence is of length `k^n`, which is best possible as it is the number of33`k`-ary strings of length `n`. One can equivalently define a De Bruijn sequence34of parameters `k` and `n` as a cyclic sequence of length `k^n` in which all35substring of length `n` are different.3637See also the `Wikipedia article on De Bruijn sequences38<http://en.wikipedia.org/wiki/De_Bruijn_sequence>`_.3940TESTS:4142Checking the sequences generated are indeed valid::4344sage: for n in range(1, 7):45... for k in range(1, 7):46... D = DeBruijnSequences(k, n)47... if not D.an_element() in D:48... print "Something's dead wrong (n=%s, k=%s)!" %(n,k)49... break5051AUTHOR:5253- Eviatar Bach (2011): initial version5455- Nathann Cohen (2011): Some work on the documentation and defined the56``__contain__`` method5758"""5960#*******************************************************************************61# Copyright (C) 2011 Eviatar Bach <[email protected]>62#63# Distributed under the terms of the GNU General Public License (GPL)64# http://www.gnu.org/licenses/65#*******************************************************************************6667include "sage/misc/bitset.pxi"6869def debruijn_sequence(int k, int n):70"""71The generating function for De Bruijn sequences. This avoids the object72creation, so is significantly faster than accessing from DeBruijnSequence.73For more information, see the documentation there. The algorithm used is74from Frank Ruskey's "Combinatorial Generation".7576INPUT:7778- ``k`` -- Arity. Must be an integer.7980- ``n`` -- Substring length. Must be an integer.8182EXAMPLES::8384sage: from sage.combinat.debruijn_sequence import debruijn_sequence85sage: debruijn_sequence(3, 1)86[0, 1, 2]87"""88global a, sequence89if k == 1:90return [0]91a = [0] * k * n92sequence = []93gen(1, 1, k, n)94return sequence9596cdef gen(int t, int p, k, n):97"""98The internal generation function. This should not be accessed by the99user.100"""101cdef int j102if t > n:103if n % p == 0:104for j in range(1, p + 1): sequence.append(a[j])105else:106a[t] = a[t - p]107gen(t + 1, p, k, n)108for j in range((a[t - p] + 1), (k)):109a[t] = j110gen(t + 1, t, k, n)111112def is_debruijn_sequence(seq, k, n):113r"""114Given a sequence of integer elements in `0..k-1`, tests whether it115corresponds to a De Bruijn sequence of parameters `k` and `n`.116117INPUT:118119- ``seq`` -- Sequence of elements in `0..k-1`.120121- ``n,k`` -- Integers.122123EXAMPLE::124125sage: from sage.combinat.debruijn_sequence import is_debruijn_sequence126sage: s = DeBruijnSequences(2, 3).an_element()127sage: is_debruijn_sequence(s, 2, 3)128True129sage: is_debruijn_sequence(s + [0], 2, 3)130False131sage: is_debruijn_sequence([1] + s[1:], 2, 3)132False133"""134135if k == 1:136return seq == [0]137138# The implementation is pretty straightforward.139140# The variable "current" is the integer representing the value of a141# substring of length n. We iterate over all the possible substrings from142# left to right, and keep track of the values met so far with the bitset143# "seen".144145cdef int i146cdef list s = seq147cdef int nn = n148cdef int kk = k149150cdef int k_p_n = kk ** nn151152cdef bitset_t seen153154# Checking if the length is correct155if len(s) != kk ** nn:156return False157158# Initializing the bitset159bitset_init(seen, k_p_n)160bitset_set_first_n(seen, 0)161162# We initialize "current" to correspond to the word formed by the (n-1) last elements163cdef int current = 0164165for i in range(n - 1):166current = kk * current + s[-n + i + 1]167168answer = True169170# Main loop, stopping if the same word has been met twice171for i in s:172current = (kk * current + i) % k_p_n173174if bitset_in(seen, current) or i < 0 or i >= k:175answer = False176break177178bitset_set(seen, current)179180bitset_free(seen)181182return answer183184from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets185from sage.rings.integer import Integer186187class DeBruijnSequences(FiniteEnumeratedSets):188"""189Represents the De Bruijn sequences of given parameters `k` and `n`.190191A De Bruijn sequence of parameters `k` and `n` is defined as the shortest192cyclic sequence that incorporates all substrings of length `n` a `k`-ary193alphabet.194195This class can be used to generate the lexicographically smallest De Bruijn196sequence, to count the number of existing De Bruijn sequences or to test197whether a given sequence is De Bruijn.198199INPUT:200201- ``k`` -- A natural number to define arity. The letters used are the202integers `0..k-1`.203204- ``n`` -- A natural number that defines the length of the substring.205206EXAMPLES:207208Obtaining a De Bruijn sequence::209210sage: seq = DeBruijnSequences(2, 3).an_element()211sage: print seq212[0, 0, 0, 1, 0, 1, 1, 1]213214Testing whether it is indeed one::215216sage: seq in DeBruijnSequences(2, 3)217True218219The total number for these parameters::220221sage: DeBruijnSequences(2, 3).cardinality()2222223224.. note::225226This function only generates one De Bruijn sequence (the smallest227lexicographically). Support for generating all possible ones may be228added in the future.229230TESTS:231232Setting ``k`` to 1 will return 0:233234::235236sage: DeBruijnSequences(1, 3).an_element()237[0]238239Setting ``n`` to 1 will return the alphabet:240241::242243sage: DeBruijnSequences(3, 1).an_element()244[0, 1, 2]245246The test suite:247248::249250sage: d=DeBruijnSequences(2, 3)251sage: TestSuite(d).run()252"""253def __init__(self, k, n):254"""255Constructor.256257Checks the consistency of the given arguments.258259TESTS:260261Setting ``n`` orr ``k`` to anything under 1 will return a ValueError:262263::264265sage: DeBruijnSequences(3, 0).an_element()266Traceback (most recent call last):267...268ValueError: k and n cannot be under 1.269270Setting ``n`` or ``k`` to any type except an integer will return a271TypeError:272273::274275sage: DeBruijnSequences(2.5, 3).an_element()276Traceback (most recent call last):277...278TypeError: k and n must be integers.279"""280if n < 1 or k < 1:281raise ValueError('k and n cannot be under 1.')282if (not isinstance(n, (Integer, int)) or283not isinstance(k, (Integer,int))):284raise TypeError('k and n must be integers.')285286self.k = k287self.n = n288289def __repr__(self):290"""291Provides a string representation of the object's parameter.292293EXAMPLE::294295sage: repr(DeBruijnSequences(4, 50))296'De Bruijn sequences with arity 4 and substring length 50'297"""298return ("De Bruijn sequences with arity %s and substring length %s"299% (self.k, self.n))300301def an_element(self):302"""303Returns the lexicographically smallest De Bruijn sequence with the given304parameters.305306ALGORITHM:307308The algorithm is described in the book "Combinatorial Generation" by309Frank Ruskey. This program is based on a Ruby implementation by Jonas310Elfström, which is based on the C program by Joe Sadawa.311312EXAMPLE::313314sage: DeBruijnSequences(2, 3).an_element()315[0, 0, 0, 1, 0, 1, 1, 1]316"""317return debruijn_sequence(self.k, self.n)318319def __contains__(self, seq):320r"""321Tests whether the given sequence is a De Bruijn sequence with322the current object's parameters.323324INPUT:325326- ``seq`` -- A sequence of integers.327328EXAMPLE:329330sage: Sequences = DeBruijnSequences(2, 3)331sage: Sequences.an_element() in Sequences332True333"""334return is_debruijn_sequence(seq, self.k, self.n)335336def cardinality(self):337"""338Returns the number of distinct De Bruijn sequences for the object's339parameters.340341EXAMPLE::342343sage: DeBruijnSequences(2, 5).cardinality()3442048345346ALGORITHM:347348The formula for cardinality is `k!^{k^{n-1}}/k^n` [1]_.349350REFERENCES:351352.. [1] Rosenfeld, Vladimir Raphael, 2002: Enumerating De Bruijn353Sequences. *Communications in Math. and in Computer Chem.*354"""355from sage.functions.other import factorial356return (factorial(self.k) ** (self.k ** (self.n - 1)))/ (self.k**self.n)357358359