103 lines
2.1 KiB
Go
103 lines
2.1 KiB
Go
|
package shuffle
|
||
|
|
||
|
import (
|
||
|
"crypto/rand"
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"math/big"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
n = 5
|
||
|
samplesNum = 300000
|
||
|
)
|
||
|
|
||
|
func factorial(n int) *big.Int {
|
||
|
return factorial_body(n, big.NewInt(1))
|
||
|
}
|
||
|
|
||
|
func factorial_body(n int, acc *big.Int) *big.Int {
|
||
|
if n == 0 {
|
||
|
return acc
|
||
|
}
|
||
|
acc.Mul(acc, big.NewInt(int64(n)))
|
||
|
return factorial_body(n-1, acc)
|
||
|
}
|
||
|
|
||
|
func ChiSquare(obs, exp []float64) (float64, error) {
|
||
|
if len(obs) != len(exp) {
|
||
|
return 0, BENCHMARK_LEN_DN_MATCH
|
||
|
}
|
||
|
var result float64
|
||
|
result = 0
|
||
|
for i, a := range obs {
|
||
|
b := exp[i]
|
||
|
if a == 0 && b == 0 {
|
||
|
continue
|
||
|
}
|
||
|
result += (a - b) * (a - b) / b
|
||
|
}
|
||
|
return result, nil
|
||
|
}
|
||
|
|
||
|
func bigChiSquare(observed []int, expected *big.Float) *big.Float {
|
||
|
chiSquare := big.NewFloat(0)
|
||
|
for _, obs := range observed {
|
||
|
obsFloat := big.NewFloat(float64(obs))
|
||
|
diff := new(big.Float).Sub(obsFloat, expected)
|
||
|
squaredDiff := new(big.Float).Mul(diff, diff)
|
||
|
term := new(big.Float).Quo(squaredDiff, expected)
|
||
|
chiSquare.Add(chiSquare, term)
|
||
|
}
|
||
|
return chiSquare
|
||
|
}
|
||
|
|
||
|
func GetBenchmarkN() int {
|
||
|
return n
|
||
|
}
|
||
|
|
||
|
func GetBenchmarkForShuffle[T Numeric](alg ShuffleNumericAlg[T], keyLen int, fullDebug bool) error {
|
||
|
perms := map[[n]T]int{}
|
||
|
for i := 0; i < samplesNum; i++ {
|
||
|
if fullDebug {
|
||
|
log.Printf("Running %d sample\n", i)
|
||
|
}
|
||
|
arr := [n]T{zeroValue[T]()}
|
||
|
for i := 0; i < n; i++ {
|
||
|
arr[i] = T(i)
|
||
|
}
|
||
|
//
|
||
|
dummyKey := make([]byte, keyLen)
|
||
|
keyN, err := rand.Read(dummyKey)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if keyN != len(dummyKey) {
|
||
|
return BENCHMARK_INTERNAL_ERROR
|
||
|
}
|
||
|
alg(arr[:], dummyKey)
|
||
|
//
|
||
|
perms[arr]++
|
||
|
}
|
||
|
fact := factorial(n)
|
||
|
factFloat := new(big.Float).SetInt(fact)
|
||
|
|
||
|
// Calculate expected value
|
||
|
samplesFloat := big.NewFloat(float64(samplesNum))
|
||
|
expectedBig := new(big.Float).Quo(samplesFloat, factFloat)
|
||
|
if fullDebug {
|
||
|
log.Printf("expectedBig is %f\n", expectedBig)
|
||
|
log.Printf("factorial is %d\n", factorial(n))
|
||
|
}
|
||
|
|
||
|
observed := make([]int, 0, len(perms))
|
||
|
for _, count := range perms {
|
||
|
// log.Printf("Getting count from perm = %d\n", count)
|
||
|
observed = append(observed, count)
|
||
|
}
|
||
|
|
||
|
val := bigChiSquare(observed, expectedBig)
|
||
|
fmt.Printf("Chi-Square value: %s\n", val.Text('f', 10))
|
||
|
return nil
|
||
|
}
|