How to resolve the algorithm De Bruijn sequences step by step in the Go programming language
How to resolve the algorithm De Bruijn sequences step by step in the Go programming language
Table of Contents
Problem Statement
The sequences are named after the Dutch mathematician Nicolaas Govert de Bruijn.
A note on Dutch capitalization: Nicolaas' last name is de Bruijn, the de isn't normally capitalized unless it's the first word in a sentence. Rosetta Code (more or less by default or by fiat) requires the first word in the task name to be capitalized.
In combinatorial mathematics, a de Bruijn sequence of order n on a size-k alphabet (computer science) A is a cyclic sequence in which every possible length-n string (computer science, formal theory) on A occurs exactly once as a contiguous substring. Such a sequence is denoted by B(k, n) and has length kn, which is also the number of distinct substrings of length n on A; de Bruijn sequences are therefore optimally short. There are: distinct de Bruijn sequences B(k, n).
For this Rosetta Code task, a de Bruijn sequence is to be generated that can be used to shorten a brute-force attack on a PIN-like code lock that does not have an "enter" key and accepts the last n digits entered.
Note: automated teller machines (ATMs) used to work like this, but their software has been updated to not allow a brute-force attack.
A digital door lock with a 4-digit code would have B (10, 4) solutions, with a length of 10,000 (digits). Therefore, only at most 10,000 + 3 (as the solutions are cyclic or wrap-around) presses are needed to open the lock. Trying all 4-digit codes separately would require 4 × 10,000 or 40,000 presses.
(The last requirement is to ensure that the verification tests performs correctly. The verification processes should list any and all missing PIN codes.) Show all output here, on this page.
Let's start with the solution:
Step by Step solution about How to resolve the algorithm De Bruijn sequences step by step in the Go programming language
The provided Go program demonstrates the generation and validation of a de Bruijn sequence, which is a combinatorial object with applications in various fields. Here's a detailed explanation of the source code:
-
Constants and Variables:
digits
: A constant string representing the digits0
to9
.a
: A byte array of lengthk*n
used to construct the de Bruijn sequence.
-
deBruijn
Function:- This function generates a de Bruijn sequence of order
k
and lengthn
. - It initializes
a
with thek
digits fromdigits
and uses a recursive closuredb
to construct the sequence. - The recursive function
db
performs the following steps:- If the current position
t
is greater thann
, it checks ifn
is divisible byp
(the previous position). If so, it appends the digits froma
at positionp
tot
to theseq
slice. - Otherwise, it copies the digit at position
t-p
to positiont
ina
and callsdb
recursively witht+1
andp
. - It iterates through the remaining digits in the range
j = a[t-p] + 1
tok
, assigns them to positiont
ina
, and callsdb
recursively witht+1
andt
.
- If the current position
- Finally, the function returns the concatenated
seq
slice and the firstn-1
digits of the sequence to form a cyclic pattern.
- This function generates a de Bruijn sequence of order
-
allDigits
Function:- This function checks if a string
s
contains only digits (0
to9
).
- This function checks if a string
-
validate
Function:- This function validates a given de Bruijn sequence
db
. - It creates a slice
found
of length 10000 to track the occurrences of all 4-digit combinations withindb
. - It iterates through all 4-digit substrings in
db
, checks if they are valid digits, and increments the corresponding count infound
. - It then checks for missing or duplicate 4-digit combinations and reports any errors found.
- This function validates a given de Bruijn sequence
-
reverse
Function:- This function reverses the order of characters in a string.
-
main
Function:- It calls the
deBruijn
function to generate a de Bruijn sequence with 10 digits and length 4 (i.e.,db
). - It prints the length of the generated sequence, the first 130 digits, and the last 130 digits.
- It validates the original de Bruijn sequence (
db
), the reversed de Bruijn sequence (dbr
), and an overlaid de Bruijn sequence where one digit is replaced with a dot ('.').
- It calls the
Source code in the go programming language
package main
import (
"bytes"
"fmt"
"strconv"
"strings"
)
const digits = "0123456789"
func deBruijn(k, n int) string {
alphabet := digits[0:k]
a := make([]byte, k*n)
var seq []byte
var db func(int, int) // recursive closure
db = func(t, p int) {
if t > n {
if n%p == 0 {
seq = append(seq, a[1:p+1]...)
}
} else {
a[t] = a[t-p]
db(t+1, p)
for j := int(a[t-p] + 1); j < k; j++ {
a[t] = byte(j)
db(t+1, t)
}
}
}
db(1, 1)
var buf bytes.Buffer
for _, i := range seq {
buf.WriteByte(alphabet[i])
}
b := buf.String()
return b + b[0:n-1] // as cyclic append first (n-1) digits
}
func allDigits(s string) bool {
for _, b := range s {
if b < '0' || b > '9' {
return false
}
}
return true
}
func validate(db string) {
le := len(db)
found := make([]int, 10000)
var errs []string
// Check all strings of 4 consecutive digits within 'db'
// to see if all 10,000 combinations occur without duplication.
for i := 0; i < le-3; i++ {
s := db[i : i+4]
if allDigits(s) {
n, _ := strconv.Atoi(s)
found[n]++
}
}
for i := 0; i < 10000; i++ {
if found[i] == 0 {
errs = append(errs, fmt.Sprintf(" PIN number %04d missing", i))
} else if found[i] > 1 {
errs = append(errs, fmt.Sprintf(" PIN number %04d occurs %d times", i, found[i]))
}
}
lerr := len(errs)
if lerr == 0 {
fmt.Println(" No errors found")
} else {
pl := "s"
if lerr == 1 {
pl = ""
}
fmt.Printf(" %d error%s found:\n", lerr, pl)
fmt.Println(strings.Join(errs, "\n"))
}
}
func reverse(s string) string {
bytes := []byte(s)
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
bytes[i], bytes[j] = bytes[j], bytes[i]
}
return string(bytes)
}
func main() {
db := deBruijn(10, 4)
le := len(db)
fmt.Println("The length of the de Bruijn sequence is", le)
fmt.Println("\nThe first 130 digits of the de Bruijn sequence are:")
fmt.Println(db[0:130])
fmt.Println("\nThe last 130 digits of the de Bruijn sequence are:")
fmt.Println(db[le-130:])
fmt.Println("\nValidating the de Bruijn sequence:")
validate(db)
fmt.Println("\nValidating the reversed de Bruijn sequence:")
dbr := reverse(db)
validate(dbr)
bytes := []byte(db)
bytes[4443] = '.'
db = string(bytes)
fmt.Println("\nValidating the overlaid de Bruijn sequence:")
validate(db)
}
You may also check:How to resolve the algorithm Video display modes step by step in the Icon and Unicon programming language
You may also check:How to resolve the algorithm Input loop step by step in the UnixPipes programming language
You may also check:How to resolve the algorithm Statistics/Normal distribution step by step in the Python programming language
You may also check:How to resolve the algorithm Musical scale step by step in the VBA programming language
You may also check:How to resolve the algorithm Repeat a string step by step in the NewLISP programming language