gonum.org/v1/gonum@v0.14.0/stat/distuv/bernoulli_test.go (about) 1 // Copyright ©2016 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package distuv 6 7 import ( 8 "math" 9 "sort" 10 "testing" 11 12 "golang.org/x/exp/rand" 13 ) 14 15 func TestBernoulli(t *testing.T) { 16 t.Parallel() 17 src := rand.New(rand.NewSource(1)) 18 for i, dist := range []Bernoulli{ 19 {P: 0.5, Src: src}, 20 {P: 0.9, Src: src}, 21 {P: 0.2, Src: src}, 22 {P: 0.0, Src: src}, 23 {P: 1.0, Src: src}, 24 } { 25 testBernoulli(t, dist, i) 26 testBernoulliCDF(t, dist) 27 testBernoulliSurvival(t, dist) 28 testBernoulliQuantile(t, dist) 29 if dist.P == 0 || dist.P == 1 { 30 entropy := dist.Entropy() 31 if entropy != 0 { 32 t.Errorf("Entropy of a Bernoulli distribution with P = %g is not zero, got: %g", dist.P, entropy) 33 } 34 } 35 if dist.NumParameters() != 1 { 36 t.Errorf("Wrong number of parameters") 37 } 38 for _, x := range []float64{-0.2, 0.5, 1.1} { 39 logP := dist.LogProb(x) 40 p := dist.Prob(x) 41 if !math.IsInf(logP, -1) { 42 t.Errorf("Log-probability for x = %g is not -Inf, got: %g", x, logP) 43 } 44 if p != 0 { 45 t.Errorf("Probability for x = %g is not 0, got: %g", x, p) 46 } 47 } 48 } 49 } 50 51 func testBernoulli(t *testing.T, dist Bernoulli, i int) { 52 const ( 53 tol = 1e-2 54 n = 3e6 55 bins = 50 56 ) 57 x := make([]float64, n) 58 generateSamples(x, dist) 59 sort.Float64s(x) 60 61 checkMean(t, i, x, dist, tol) 62 checkVarAndStd(t, i, x, dist, tol) 63 checkEntropy(t, i, x, dist, tol) 64 checkProbDiscrete(t, i, x, dist, tol) 65 if dist.P != 0 && dist.P != 1 { 66 // Sample kurtosis and skewness are going to be NaN for P = 0 or 1. 67 checkExKurtosis(t, i, x, dist, tol) 68 checkSkewness(t, i, x, dist, tol) 69 } else { 70 if !math.IsInf(dist.ExKurtosis(), 1) { 71 t.Errorf("Excess kurtosis for P == 0 or 1 is not +Inf") 72 } 73 skewness := dist.Skewness() 74 if dist.P == 0 { 75 if !math.IsInf(skewness, 1) { 76 t.Errorf("Skewness for P == 0 is not +Inf") 77 } 78 } else { 79 if !math.IsInf(skewness, -1) { 80 t.Errorf("Skewness for P == 1 is not -Inf") 81 } 82 } 83 } 84 if dist.P != 0.5 { 85 checkMedian(t, i, x, dist, tol) 86 } else if dist.Median() != 0.5 { 87 t.Errorf("Median for P == 0.5 is not 0.5") 88 } 89 } 90 91 func testBernoulliCDF(t *testing.T, dist Bernoulli) { 92 if dist.CDF(-0.000001) != 0 { 93 t.Errorf("Bernoulli CDF below zero is not zero") 94 } 95 if dist.CDF(0) != 1-dist.P { 96 t.Errorf("Bernoulli CDF at zero is not 1 - P(1)") 97 } 98 if dist.CDF(0.0001) != 1-dist.P { 99 t.Errorf("Bernoulli CDF between zero and one is not 1 - P(1)") 100 } 101 if dist.CDF(0.9999) != 1-dist.P { 102 t.Errorf("Bernoulli CDF between zero and one is not 1 - P(1)") 103 } 104 if dist.CDF(1) != 1 { 105 t.Errorf("Bernoulli CDF at one is not one") 106 } 107 if dist.CDF(1.00001) != 1 { 108 t.Errorf("Bernoulli CDF above one is not one") 109 } 110 } 111 112 func testBernoulliSurvival(t *testing.T, dist Bernoulli) { 113 if dist.Survival(-0.000001) != 1 { 114 t.Errorf("Bernoulli Survival below zero is not one") 115 } 116 if dist.Survival(0) != dist.P { 117 t.Errorf("Bernoulli Survival at zero is not P(1)") 118 } 119 if dist.Survival(0.0001) != dist.P { 120 t.Errorf("Bernoulli Survival between zero and one is not P(1)") 121 } 122 if dist.Survival(1) != 0 { 123 t.Errorf("Bernoulli Survival at one is not zero") 124 } 125 if dist.Survival(1.00001) != 0 { 126 t.Errorf("Bernoulli Survival above one is not zero") 127 } 128 } 129 130 func testBernoulliQuantile(t *testing.T, dist Bernoulli) { 131 if !panics(func() { dist.Quantile(-0.0001) }) { 132 t.Errorf("Expected panic with negative argument") 133 } 134 if !panics(func() { dist.Quantile(1.0001) }) { 135 t.Errorf("Expected panic with argument above 1") 136 } 137 for _, x := range []float64{0., 1.} { 138 want := x 139 if dist.P == 0 { 140 want = 0 141 } 142 if dist.Quantile(dist.CDF(x)) != want { 143 t.Errorf("Quantile(CDF(x)) not equal to %g for x = %g for P = %g", want, x, dist.P) 144 } 145 } 146 expectedQuantile1 := 1. 147 if dist.P == 0 { 148 expectedQuantile1 = 0. 149 } 150 if dist.Quantile(1) != expectedQuantile1 { 151 t.Errorf("Quantile at 1 not equal to 1 for P = %g", dist.P) 152 } 153 eps := 1e-12 154 if dist.P > eps && dist.P < 1-eps { 155 if dist.Quantile(1-dist.P-eps) != 0 { 156 t.Errorf("Quantile slightly below 0 < 1-P < 1 is not zero") 157 } 158 if dist.Quantile(1-dist.P+eps) != 1 { 159 t.Errorf("Quantile slightly above 0 < 1-P < 1 is not one") 160 } 161 if dist.Quantile(1-dist.P) != 0 { 162 t.Errorf("Quantile at 0 < 1-P < 1 is not zero") 163 } 164 } 165 }