Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/combinat/debruijn_sequence.pyx
4056 views
1
# -*- coding: utf-8 -*-
2
r"""
3
De Bruijn sequences
4
5
A De Bruijn sequence is defined as the shortest cyclic sequence that
6
incorporates all substrings of a certain length of an alphabet.
7
8
For instance, the `2^3=8` binary strings of length 3 are all included in the
9
following string::
10
11
sage: DeBruijnSequences(2,3).an_element()
12
[0, 0, 0, 1, 0, 1, 1, 1]
13
14
They can be obtained as a subsequence of the *cyclic* De Bruijn sequence of
15
parameters `k=2` and `n=3`::
16
17
sage: seq = DeBruijnSequences(2,3).an_element()
18
sage: print Word(seq).string_rep()
19
00010111
20
sage: shift = lambda i: [(i+j)%2**3 for j in range(3)]
21
sage: for i in range(2**3):
22
... print (Word(map(lambda (j,b): b if j in shift(i) else '*',
23
... enumerate(seq))).string_rep())
24
000*****
25
*001****
26
**010***
27
***101**
28
****011*
29
*****111
30
0*****11
31
00*****1
32
33
This sequence is of length `k^n`, which is best possible as it is the number of
34
`k`-ary strings of length `n`. One can equivalently define a De Bruijn sequence
35
of parameters `k` and `n` as a cyclic sequence of length `k^n` in which all
36
substring of length `n` are different.
37
38
See also the `Wikipedia article on De Bruijn sequences
39
<http://en.wikipedia.org/wiki/De_Bruijn_sequence>`_.
40
41
TESTS:
42
43
Checking the sequences generated are indeed valid::
44
45
sage: for n in range(1, 7):
46
... for k in range(1, 7):
47
... D = DeBruijnSequences(k, n)
48
... if not D.an_element() in D:
49
... print "Something's dead wrong (n=%s, k=%s)!" %(n,k)
50
... break
51
52
AUTHOR:
53
54
- Eviatar Bach (2011): initial version
55
56
- Nathann Cohen (2011): Some work on the documentation and defined the
57
``__contain__`` method
58
59
"""
60
61
#*******************************************************************************
62
# Copyright (C) 2011 Eviatar Bach <[email protected]>
63
#
64
# Distributed under the terms of the GNU General Public License (GPL)
65
# http://www.gnu.org/licenses/
66
#*******************************************************************************
67
68
include "../misc/bitset.pxi"
69
70
def debruijn_sequence(int k, int n):
71
"""
72
The generating function for De Bruijn sequences. This avoids the object
73
creation, so is significantly faster than accessing from DeBruijnSequence.
74
For more information, see the documentation there. The algorithm used is
75
from Frank Ruskey's "Combinatorial Generation".
76
77
INPUT:
78
79
- ``k`` -- Arity. Must be an integer.
80
81
- ``n`` -- Substring length. Must be an integer.
82
83
EXAMPLES::
84
85
sage: from sage.combinat.debruijn_sequence import debruijn_sequence
86
sage: debruijn_sequence(3, 1)
87
[0, 1, 2]
88
"""
89
global a, sequence
90
if k == 1:
91
return [0]
92
a = [0] * k * n
93
sequence = []
94
gen(1, 1, k, n)
95
return sequence
96
97
cdef gen(int t, int p, k, n):
98
"""
99
The internal generation function. This should not be accessed by the
100
user.
101
"""
102
cdef int j
103
if t > n:
104
if n % p == 0:
105
for j in range(1, p + 1): sequence.append(a[j])
106
else:
107
a[t] = a[t - p]
108
gen(t + 1, p, k, n)
109
for j in range((a[t - p] + 1), (k)):
110
a[t] = j
111
gen(t + 1, t, k, n)
112
113
def is_debruijn_sequence(seq, k, n):
114
r"""
115
Given a sequence of integer elements in `0..k-1`, tests whether it
116
corresponds to a De Bruijn sequence of parameters `k` and `n`.
117
118
INPUT:
119
120
- ``seq`` -- Sequence of elements in `0..k-1`.
121
122
- ``n,k`` -- Integers.
123
124
EXAMPLE::
125
126
sage: from sage.combinat.debruijn_sequence import is_debruijn_sequence
127
sage: s = DeBruijnSequences(2, 3).an_element()
128
sage: is_debruijn_sequence(s, 2, 3)
129
True
130
sage: is_debruijn_sequence(s + [0], 2, 3)
131
False
132
sage: is_debruijn_sequence([1] + s[1:], 2, 3)
133
False
134
"""
135
136
if k == 1:
137
return seq == [0]
138
139
# The implementation is pretty straightforward.
140
141
# The variable "current" is the integer representing the value of a
142
# substring of length n. We iterate over all the possible substrings from
143
# left to right, and keep track of the values met so far with the bitset
144
# "seen".
145
146
cdef int i
147
cdef list s = seq
148
cdef int nn = n
149
cdef int kk = k
150
151
cdef int k_p_n = kk ** nn
152
153
cdef bitset_t seen
154
155
# Checking if the length is correct
156
if len(s) != kk ** nn:
157
return False
158
159
# Initializing the bitset
160
bitset_init(seen, k_p_n)
161
bitset_set_first_n(seen, 0)
162
163
# We initialize "current" to correspond to the word formed by the (n-1) last elements
164
cdef int current = 0
165
166
for i in range(n - 1):
167
current = kk * current + s[-n + i + 1]
168
169
answer = True
170
171
# Main loop, stopping if the same word has been met twice
172
for i in s:
173
current = (kk * current + i) % k_p_n
174
175
if bitset_in(seen, current) or i < 0 or i >= k:
176
answer = False
177
break
178
179
bitset_set(seen, current)
180
181
bitset_free(seen)
182
183
return answer
184
185
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
186
from sage.rings.integer import Integer
187
188
class DeBruijnSequences(FiniteEnumeratedSets):
189
"""
190
Represents the De Bruijn sequences of given parameters `k` and `n`.
191
192
A De Bruijn sequence of parameters `k` and `n` is defined as the shortest
193
cyclic sequence that incorporates all substrings of length `n` a `k`-ary
194
alphabet.
195
196
This class can be used to generate the lexicographically smallest De Bruijn
197
sequence, to count the number of existing De Bruijn sequences or to test
198
whether a given sequence is De Bruijn.
199
200
INPUT:
201
202
- ``k`` -- A natural number to define arity. The letters used are the
203
integers `0..k-1`.
204
205
- ``n`` -- A natural number that defines the length of the substring.
206
207
EXAMPLES:
208
209
Obtaining a De Bruijn sequence::
210
211
sage: seq = DeBruijnSequences(2, 3).an_element()
212
sage: print seq
213
[0, 0, 0, 1, 0, 1, 1, 1]
214
215
Testing whether it is indeed one::
216
217
sage: seq in DeBruijnSequences(2, 3)
218
True
219
220
The total number for these parameters::
221
222
sage: DeBruijnSequences(2, 3).cardinality()
223
2
224
225
.. note::
226
227
This function only generates one De Bruijn sequence (the smallest
228
lexicographically). Support for generating all possible ones may be
229
added in the future.
230
231
TESTS:
232
233
Setting ``k`` to 1 will return 0:
234
235
::
236
237
sage: DeBruijnSequences(1, 3).an_element()
238
[0]
239
240
Setting ``n`` to 1 will return the alphabet:
241
242
::
243
244
sage: DeBruijnSequences(3, 1).an_element()
245
[0, 1, 2]
246
247
The test suite:
248
249
::
250
251
sage: d=DeBruijnSequences(2, 3)
252
sage: TestSuite(d).run()
253
"""
254
def __init__(self, k, n):
255
"""
256
Constructor.
257
258
Checks the consistency of the given arguments.
259
260
TESTS:
261
262
Setting ``n`` orr ``k`` to anything under 1 will return a ValueError:
263
264
::
265
266
sage: DeBruijnSequences(3, 0).an_element()
267
Traceback (most recent call last):
268
...
269
ValueError: k and n cannot be under 1.
270
271
Setting ``n`` or ``k`` to any type except an integer will return a
272
TypeError:
273
274
::
275
276
sage: DeBruijnSequences(2.5, 3).an_element()
277
Traceback (most recent call last):
278
...
279
TypeError: k and n must be integers.
280
"""
281
if n < 1 or k < 1:
282
raise ValueError('k and n cannot be under 1.')
283
if (not isinstance(n, (Integer, int)) or
284
not isinstance(k, (Integer,int))):
285
raise TypeError('k and n must be integers.')
286
287
self.k = k
288
self.n = n
289
290
def __repr__(self):
291
"""
292
Provides a string representation of the object's parameter.
293
294
EXAMPLE::
295
296
sage: repr(DeBruijnSequences(4, 50))
297
'De Bruijn sequences with arity 4 and substring length 50'
298
"""
299
return ("De Bruijn sequences with arity %s and substring length %s"
300
% (self.k, self.n))
301
302
def an_element(self):
303
"""
304
Returns the lexicographically smallest De Bruijn sequence with the given
305
parameters.
306
307
ALGORITHM:
308
309
The algorithm is described in the book "Combinatorial Generation" by
310
Frank Ruskey. This program is based on a Ruby implementation by Jonas
311
Elfström, which is based on the C program by Joe Sadawa.
312
313
EXAMPLE::
314
315
sage: DeBruijnSequences(2, 3).an_element()
316
[0, 0, 0, 1, 0, 1, 1, 1]
317
"""
318
return debruijn_sequence(self.k, self.n)
319
320
def __contains__(self, seq):
321
r"""
322
Tests whether the given sequence is a De Bruijn sequence with
323
the current object's parameters.
324
325
INPUT:
326
327
- ``seq`` -- A sequence of integers.
328
329
EXAMPLE:
330
331
sage: Sequences = DeBruijnSequences(2, 3)
332
sage: Sequences.an_element() in Sequences
333
True
334
"""
335
return is_debruijn_sequence(seq, self.k, self.n)
336
337
def cardinality(self):
338
"""
339
Returns the number of distinct De Bruijn sequences for the object's
340
parameters.
341
342
EXAMPLE::
343
344
sage: DeBruijnSequences(2, 5).cardinality()
345
2048
346
347
ALGORITHM:
348
349
The formula for cardinality is `k!^{k^{n-1}}/k^n` [1]_.
350
351
REFERENCES:
352
353
.. [1] Rosenfeld, Vladimir Raphael, 2002: Enumerating De Bruijn
354
Sequences. *Communications in Math. and in Computer Chem.*
355
"""
356
from sage.functions.other import factorial
357
return (factorial(self.k) ** (self.k ** (self.n - 1)))/ (self.k**self.n)
358
359