initial import
This commit is contained in:
14
core/mathx/entropy.go
Normal file
14
core/mathx/entropy.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package mathx
|
||||
|
||||
import "math"
|
||||
|
||||
func CalcEntropy(m map[interface{}]int, total int) float64 {
|
||||
var entropy float64
|
||||
|
||||
for _, v := range m {
|
||||
proba := float64(v) / float64(total)
|
||||
entropy -= proba * math.Log2(proba)
|
||||
}
|
||||
|
||||
return entropy / math.Log2(float64(len(m)))
|
||||
}
|
||||
17
core/mathx/entropy_test.go
Normal file
17
core/mathx/entropy_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package mathx
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCalcEntropy(t *testing.T) {
|
||||
const total = 1000
|
||||
const count = 100
|
||||
m := make(map[interface{}]int, total)
|
||||
for i := 0; i < total; i++ {
|
||||
m[i] = count
|
||||
}
|
||||
assert.True(t, CalcEntropy(m, total*count) > .99)
|
||||
}
|
||||
17
core/mathx/int.go
Normal file
17
core/mathx/int.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package mathx
|
||||
|
||||
func MaxInt(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
} else {
|
||||
return b
|
||||
}
|
||||
}
|
||||
|
||||
func MinInt(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
} else {
|
||||
return b
|
||||
}
|
||||
}
|
||||
71
core/mathx/int_test.go
Normal file
71
core/mathx/int_test.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package mathx
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"zero/core/stringx"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMaxInt(t *testing.T) {
|
||||
cases := []struct {
|
||||
a int
|
||||
b int
|
||||
expect int
|
||||
}{
|
||||
{
|
||||
a: 0,
|
||||
b: 1,
|
||||
expect: 1,
|
||||
},
|
||||
{
|
||||
a: 0,
|
||||
b: -1,
|
||||
expect: 0,
|
||||
},
|
||||
{
|
||||
a: 1,
|
||||
b: 1,
|
||||
expect: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, each := range cases {
|
||||
t.Run(stringx.Rand(), func(t *testing.T) {
|
||||
actual := MaxInt(each.a, each.b)
|
||||
assert.Equal(t, each.expect, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMinInt(t *testing.T) {
|
||||
cases := []struct {
|
||||
a int
|
||||
b int
|
||||
expect int
|
||||
}{
|
||||
{
|
||||
a: 0,
|
||||
b: 1,
|
||||
expect: 0,
|
||||
},
|
||||
{
|
||||
a: 0,
|
||||
b: -1,
|
||||
expect: -1,
|
||||
},
|
||||
{
|
||||
a: 1,
|
||||
b: 1,
|
||||
expect: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, each := range cases {
|
||||
t.Run(stringx.Rand(), func(t *testing.T) {
|
||||
actual := MinInt(each.a, each.b)
|
||||
assert.Equal(t, each.expect, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
26
core/mathx/proba.go
Normal file
26
core/mathx/proba.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package mathx
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Proba struct {
|
||||
// rand.New(...) returns a non thread safe object
|
||||
r *rand.Rand
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func NewProba() *Proba {
|
||||
return &Proba{
|
||||
r: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Proba) TrueOnProba(proba float64) (truth bool) {
|
||||
p.lock.Lock()
|
||||
truth = p.r.Float64() < proba
|
||||
p.lock.Unlock()
|
||||
return
|
||||
}
|
||||
24
core/mathx/proba_test.go
Normal file
24
core/mathx/proba_test.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package mathx
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTrueOnProba(t *testing.T) {
|
||||
const proba = math.Pi / 10
|
||||
const total = 100000
|
||||
const epsilon = 0.05
|
||||
var count int
|
||||
p := NewProba()
|
||||
for i := 0; i < total; i++ {
|
||||
if p.TrueOnProba(proba) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
ratio := float64(count) / float64(total)
|
||||
assert.InEpsilon(t, proba, ratio, epsilon)
|
||||
}
|
||||
41
core/mathx/unstable.go
Normal file
41
core/mathx/unstable.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package mathx
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Unstable struct {
|
||||
deviation float64
|
||||
r *rand.Rand
|
||||
lock *sync.Mutex
|
||||
}
|
||||
|
||||
func NewUnstable(deviation float64) Unstable {
|
||||
if deviation < 0 {
|
||||
deviation = 0
|
||||
}
|
||||
if deviation > 1 {
|
||||
deviation = 1
|
||||
}
|
||||
return Unstable{
|
||||
deviation: deviation,
|
||||
r: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||
lock: new(sync.Mutex),
|
||||
}
|
||||
}
|
||||
|
||||
func (u Unstable) AroundDuration(base time.Duration) time.Duration {
|
||||
u.lock.Lock()
|
||||
val := time.Duration((1 + u.deviation - 2*u.deviation*u.r.Float64()) * float64(base))
|
||||
u.lock.Unlock()
|
||||
return val
|
||||
}
|
||||
|
||||
func (u Unstable) AroundInt(base int64) int64 {
|
||||
u.lock.Lock()
|
||||
val := int64((1 + u.deviation - 2*u.deviation*u.r.Float64()) * float64(base))
|
||||
u.lock.Unlock()
|
||||
return val
|
||||
}
|
||||
71
core/mathx/unstable_test.go
Normal file
71
core/mathx/unstable_test.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package mathx
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUnstable_AroundDuration(t *testing.T) {
|
||||
unstable := NewUnstable(0.05)
|
||||
for i := 0; i < 1000; i++ {
|
||||
val := unstable.AroundDuration(time.Second)
|
||||
assert.True(t, float64(time.Second)*0.95 <= float64(val))
|
||||
assert.True(t, float64(val) <= float64(time.Second)*1.05)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnstable_AroundInt(t *testing.T) {
|
||||
const target = 10000
|
||||
unstable := NewUnstable(0.05)
|
||||
for i := 0; i < 1000; i++ {
|
||||
val := unstable.AroundInt(target)
|
||||
assert.True(t, float64(target)*0.95 <= float64(val))
|
||||
assert.True(t, float64(val) <= float64(target)*1.05)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnstable_AroundIntLarge(t *testing.T) {
|
||||
const target int64 = 10000
|
||||
unstable := NewUnstable(5)
|
||||
for i := 0; i < 1000; i++ {
|
||||
val := unstable.AroundInt(target)
|
||||
assert.True(t, 0 <= val)
|
||||
assert.True(t, val <= 2*target)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnstable_AroundIntNegative(t *testing.T) {
|
||||
const target int64 = 10000
|
||||
unstable := NewUnstable(-0.05)
|
||||
for i := 0; i < 1000; i++ {
|
||||
val := unstable.AroundInt(target)
|
||||
assert.Equal(t, target, val)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnstable_Distribution(t *testing.T) {
|
||||
const (
|
||||
seconds = 10000
|
||||
total = 10000
|
||||
)
|
||||
|
||||
m := make(map[int]int)
|
||||
expiry := NewUnstable(0.05)
|
||||
for i := 0; i < total; i++ {
|
||||
val := int(expiry.AroundInt(seconds))
|
||||
m[val]++
|
||||
}
|
||||
|
||||
_, ok := m[0]
|
||||
assert.False(t, ok)
|
||||
|
||||
mi := make(map[interface{}]int, len(m))
|
||||
for k, v := range m {
|
||||
mi[k] = v
|
||||
}
|
||||
entropy := CalcEntropy(mi, total)
|
||||
assert.True(t, len(m) > 1)
|
||||
assert.True(t, entropy > 0.95)
|
||||
}
|
||||
Reference in New Issue
Block a user