Skip to content

Instantly share code, notes, and snippets.

@rossdylan
Created April 24, 2014 22:10
Show Gist options
  • Save rossdylan/11271226 to your computer and use it in GitHub Desktop.
Save rossdylan/11271226 to your computer and use it in GitHub Desktop.
Silly way of generating all combinations of all permutations
package cluster
import (
"math/big"
"strings"
)
// Defines a chunk of search space
// Used to tell worker processes what to work on
type Chunk struct {
ChunkID int
ComboStart big.Int
ComboEnd big.Int
SearchSpace string
KeyLength int
}
// Simple recursive factorial function operating on *big.Int
func Factorial(n int64) *big.Int {
if n < 0 {
return big.NewInt(1)
}
if n == 0 {
return big.NewInt(1)
}
bigN := big.NewInt(n)
return bigN.Mul(bigN, Factorial(n-1))
}
// Given a searchSpace generate all possible permutations and dump them into a channel
func GenreatePermutations(searchSpace []string, resultsChan chan string) {
var permLength = len(searchSpace)
permutation := make([]string, permLength)
copy(permutation, searchSpace)
for {
var greatestK = -1
var greatestL = -1
for index, value := range permutation {
if value < permutation[index+1] {
greatestK = index
}
}
if greatestK == -1 {
// No more permutations
resultsChan <- ""
break
}
for index, value := range permutation {
if permutation[greatestK] < value {
greatestL = index
}
}
permutation[greatestK], permutation[greatestL] = permutation[greatestL], permutation[greatestK]
var reverseIndex = 0
for index, _ := range permutation[greatestK+1:] {
permutation[index], permutation[permLength-reverseIndex-1] = permutation[permLength-reverseIndex-1], permutation[index]
}
resultsChan <- strings.Join(permutation, "")
}
}
// This function takes in a bunch of information and spits out Chunk structs
// The Chunk struct is used to tell workers what to work on
// This function is in charge of figuring out how many chunks to make
// and then generates them and puts them into a channel to be consumed by the work assigner
func GenerateChunks(searchSpace string, keyLength, chunkSize int, chunkChan chan Chunk) {
maxCombos := NumCombinations(int64(len(searchSpace)), int64(keyLength))
bigChunkSize := big.NewInt(int64(chunkSize))
idCount := 0
for index := big.NewInt(0); index.Cmp(maxCombos) < 0; index.Add(index, bigChunkSize) {
end := big.NewInt(0)
end.Add(index, bigChunkSize)
newChunk := Chunk{idCount, *index, *end, searchSpace, keyLength}
chunkChan <- newChunk
}
}
// Figure out the Nth combo of a keyLength-Combination of searchSpace
func NthCombo(searchSpace string, keyLength, Nth *big.Int) ([]int, string) {
combo := make([]string, keyLength)
intCombo := make([]int, keyLength)
searchSpaceLen := big.NewInt(len(searchSpace))
maximum := Nth
for index := big.NewInt(0); index.Cmp(index, KeyLength) < 0; index.Add(index, big.NewInt(1)) {
greatestN := big.NewInt(0)
greatestIndex := big.NewInt(0)
for i := big.NewInt(1); i.Cmp(i, searchSpaceLen) < 0; i.Add(i, 1) {
numCombos := NumCombinations(i, int64(keyLength-index))
if numCombos.Cmp(big.NewInt(maximum)) <= 0 {
greatestN = numCombos
greatestIndex = i
} else {
maximum = maximum - int64(greatestN.Uint64())
break
}
}
combo[keyLength-index-1] = string(searchSpace[greatestIndex])
intCombo[keyLength-index-1] = int(greatestIndex)
}
return intCombo, strings.Join(combo, "")
}
//Figure out the number of possible keyLength-combinations for searchSpace
func NumCombinations(searchSpace int64, keyLength int64) *big.Int {
//keyLength == k
//((n k))
n := searchSpace
top := Factorial(n + keyLength - 1)
kFactorial := Factorial(keyLength)
n1Factorial := Factorial(n - 1)
bottom := kFactorial.Mul(kFactorial, n1Factorial)
combos := top.Div(top, bottom)
return combos
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment