blob: f979d9bd2dd33f014d30d50f9d02101c4971d956 [file] [log] [blame]
// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fountain
import (
"math"
"math/rand"
"reflect"
"testing"
)
func almostEqual(a, b float64) bool {
return math.Abs(a-b) < 1e-5
}
func TestSolitonDistribution(t *testing.T) {
// Test several randomly chosen values of n.
tests := make([]int, 100)
for i := range tests {
tests[i] = rand.Intn(1e3) + 1 // Add 1 so that n will never be 0.
}
// Plus a couple of specific ones.
tests = append(tests, 1, 10)
for _, n := range tests {
cdf := solitonDistribution(n)
if len(cdf) != n+1 {
t.Errorf("n=%d: Wrong length CDF: %d", n, len(cdf))
t.Log("CDF=", cdf)
}
if !almostEqual(cdf[n], 1) {
t.Errorf("n=%d: CDF[max] = %f, should be 1", n, cdf[n])
t.Log("CDF=", cdf)
}
if !almostEqual(cdf[0], 0) {
t.Errorf("n=%d: CDF[0] = %f, should be 0.0", n, cdf[0])
t.Log("CDF=", cdf)
}
if !almostEqual(cdf[1], 1/float64(n)) {
t.Errorf("n=%d: CDF[1] = %f, should be 1/n (=%f)", n, cdf[1], 1/float64(n))
t.Log("CDF=", cdf)
}
}
}
func TestRobustSolitonDistribution(t *testing.T) {
cdf := robustSolitonDistribution(10, 8, 0.1)
if len(cdf) != 11 {
t.Errorf("Wrong length CDF: %d, should be 11", len(cdf))
t.Log("CDF=", cdf)
}
if !almostEqual(cdf[0], 0) {
t.Errorf("CDF[0] = %f, should be 0.0", cdf[0])
t.Log("CDF=", cdf)
}
if !almostEqual(cdf[1], .287474) {
t.Errorf("CDF[1] = %f, should be 0.287474", cdf[1])
t.Log("CDF=", cdf)
}
if !almostEqual(cdf[len(cdf)-1], 1) {
t.Errorf("CDF[max] = %f, should be very nearly 1", cdf[9])
t.Log("CDF=", cdf)
}
if (cdf[8]-cdf[7] < cdf[7]-cdf[6]) ||
(cdf[8]-cdf[7] < cdf[9]-cdf[8]) {
t.Errorf("CDF must have mode at M position(8): %v", cdf)
t.Logf("PDF[7, 8, 9] = %v, %v, %v", cdf[7]-cdf[6], cdf[8]-cdf[7], cdf[9]-cdf[8])
t.Log("CDF=", cdf)
}
}
func TestOnlineSolitonDistribution(t *testing.T) {
cdf := onlineSolitonDistribution(0.1)
if len(cdf) != 118 {
t.Errorf("Wrong length CDF: %d. Should be 118", len(cdf))
t.Log("CDF=", cdf)
}
if (cdf[2] - cdf[1]) < (cdf[1] - cdf[0]) {
t.Errorf("CDF should have mode in second position: %v", cdf[0:5])
t.Log("CDF=", cdf)
}
if !almostEqual(cdf[0], 0) {
t.Errorf("CDF[0] = %f, should be 0.0", cdf[0])
t.Log("CDF=", cdf)
}
if !almostEqual(cdf[len(cdf)-1], 1) {
t.Errorf("CDF[max] = %f, should be very nearly 1", cdf[len(cdf)-1])
t.Log("CDF=", cdf)
}
cdf = onlineSolitonDistribution(0.01)
if len(cdf) != 2116 {
t.Errorf("Wrong length CDF for 0.0: %d, should be 2116", len(cdf))
}
}
func TestPickDegree(t *testing.T) {
cdf := onlineSolitonDistribution(0.25)
random := rand.New(rand.NewSource(25))
var numLessThanFive int
for i := 0; i < 100; i++ {
d := pickDegree(random, cdf)
if d < 1 || d > len(cdf)-1 {
t.Errorf("Degree out of bounds: %d", d)
}
if d < 5 {
numLessThanFive++
}
}
if numLessThanFive < 80 {
t.Errorf("Too many large degrees: %d, should be < 80", numLessThanFive)
}
}
func TestSampleUniform(t *testing.T) {
random := rand.New(rand.NewSource(256))
var sampleTests = []struct {
num int
length int
expectedSamples []int
}{
{2, 5, []int{0, 4}},
{2, 2, []int{0, 1}},
{12, 2, []int{0, 1}},
}
for _, i := range sampleTests {
out := sampleUniform(random, i.num, i.length)
if !reflect.DeepEqual(out, i.expectedSamples) {
t.Errorf("Bad sample. Got %v, want %v", out, i.expectedSamples)
}
}
}
func TestPartition(t *testing.T) {
var partitionTests = []struct {
totalSize int
numPartitions int
numLong, numShort, lenLong, lenShort int
}{
{100, 10, 0, 10, 0, 10},
{100, 9, 1, 8, 12, 11},
{100, 11, 1, 10, 10, 9},
}
for _, i := range partitionTests {
il, is, jl, js := partition(i.totalSize, i.numPartitions)
if jl+js != i.numPartitions {
t.Errorf("Total blocks = %d, must be %d", il+jl, i.numPartitions)
}
if il*jl+is*js != i.totalSize {
t.Errorf("Total sampled size = %d, must be %d", il*jl+is*js, i.totalSize)
}
if jl != i.numLong {
t.Errorf("Bad number of long blocks. got %d, want %d", jl, i.numLong)
}
if js != i.numShort {
t.Errorf("Bad number of short blocks. got %d, want %d", js, i.numShort)
}
if il != i.lenLong {
t.Errorf("Bad long block length. got %d, want %d", il, i.lenLong)
}
if is != i.lenShort {
t.Errorf("Bad short block length. got %d, want %d", is, i.lenShort)
}
}
}
func TestFactorial(t *testing.T) {
var factorialTests = []struct {
x int
f int
}{
{0, 1},
{1, 1},
{5, 120},
{10, 3628800},
{14, 87178291200},
}
for _, test := range factorialTests {
if test.f != factorial(test.x) {
t.Errorf("%d! = %d, should be %d", test.x, factorial(test.x), test.f)
}
}
}
func TestBinomial(t *testing.T) {
var binomialTests = []struct {
x int
b int
}{
{2, 2},
{6, 20},
{7, 35},
{11, 462},
{12, 924},
}
for _, test := range binomialTests {
if test.b != centerBinomial(test.x) {
t.Errorf("(%d, %d/2) = %d, should be %d", test.x, test.x, centerBinomial(test.x), test.b)
}
}
}
func TestChoose(t *testing.T) {
var chooseTests = []struct {
n int
k int
comb int
}{
{0, 0, 1},
{1, 0, 1},
{2, 1, 2},
{7, 2, factorial(7) / (factorial(5) * factorial(2))},
{5, 3, factorial(5) / (factorial(2) * factorial(3))},
{12, 7, factorial(12) / (factorial(5) * factorial(7))},
{12, 1, 12},
{12, 2, 66},
{52, 5, 2598960},
{52, 1, 52},
{52, 52, 1},
{52, 0, 1},
}
for _, test := range chooseTests {
if choose(test.n, test.k) != test.comb {
t.Errorf("choose(%d, %d) = %d, should be %d",
test.n, test.k, choose(test.n, test.k), test.comb)
}
}
}
func TestBitSet(t *testing.T) {
var bitTests = []struct {
x uint
b uint
equal bool
}{
{0, 0, false},
{0, 1, false},
{1, 0, true},
{7, 1, true},
{16, 3, false},
{16, 4, true},
{16, 5, false},
{0x1000, 12, true},
{0x4000, 14, true},
{0x4000, 15, false},
}
for _, test := range bitTests {
if bitSet(test.x, test.b) != test.equal {
t.Errorf("%d bit set in %d = %t, should be %t", test.b, test.x, bitSet(test.x, test.b), test.equal)
}
}
}
// simpleBitsSet returns how many bits in x are set.
func simpleBitsSet(x uint64) int {
var count int
var i uint64
s := uint64(1)
for i = 0; i < 64; i++ {
if (x & s) != 0 {
count++
}
s <<= 1
}
return count
}
func TestBitsSet(t *testing.T) {
var bitsSetTests = []struct {
x uint64
b int
}{
{0, 0},
{1, 1},
{2, 1},
{4, 1},
{6, 2},
{7, 3},
{11, 3},
{12, 2},
{1<<63 | 1<<62, 2},
{0x66666666, 16},
{0x46464646, 4*1 + 4*2},
{0xffdd4411, 2*4 + 2*3 + 2*1 + 2*1},
}
for _, test := range bitsSetTests {
if test.b != bitsSet(test.x) {
t.Errorf("bits set in %d = %d, should be %d", test.x, bitsSet(test.x), test.b)
}
}
for i := 0; i < 1000; i++ {
x := uint64(rand.Int63())
if simpleBitsSet(x) != bitsSet(x) {
t.Errorf("bits set in %d = %d, should be %d", x, bitsSet(x), simpleBitsSet(x))
}
}
}
func TestGrayCode(t *testing.T) {
var grayTests = []struct {
x uint64
g uint64
}{
{0, 0},
{1, 1},
{2, 3},
{5, 7},
{6, 5},
{9, 13},
}
for _, test := range grayTests {
if test.g != grayCode(test.x) {
t.Errorf("grayCode(%d) = %d, should be %d", test.x, grayCode(test.x), test.g)
}
}
}
func TestGraySequence(t *testing.T) {
var grayTests = []struct {
length int
b int
seq []int
}{
{4, 3, []int{7, 13, 14, 11}},
{6, 2, []int{3, 6, 5, 12, 10, 9}},
}
for _, test := range grayTests {
if !reflect.DeepEqual(buildGraySequence(test.length, test.b), test.seq) {
t.Errorf("gray sequence for %d = %v, should be %v", test.b, buildGraySequence(test.length, test.b), test.seq)
}
}
}
func TestSmallestPrime(t *testing.T) {
var primeTests = []struct {
x int
p int
}{
{0, 2},
{1, 2},
{2, 2},
{20, 23},
{1426, 1427},
{1427, 1427},
{1427, 1427},
{1997, 1997},
{1998, 1999},
{1999, 1999},
{3301, 3301},
{8522, 8527},
}
for _, test := range primeTests {
if test.p != smallestPrimeGreaterOrEqual(test.x) {
t.Errorf("smallestPrimeGreaterOrEqual(%d) = %d, should be %d", test.x, smallestPrimeGreaterOrEqual(test.x), test.p)
}
}
}
func TestIsPrime(t *testing.T) {
var primeTests = []struct {
x int
prime bool
}{
{2000, false},
{2099, true},
{2607, false},
{9007, true},
}
for _, test := range primeTests {
if test.prime != isPrime(test.x) {
t.Errorf("isPrime(%d) = %t, should be %t", test.x, isPrime(test.x), test.prime)
}
}
}