gonum.org/v1/gonum@v0.14.0/stat/distuv/beta_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 "gonum.org/v1/gonum/floats/scalar" 15 ) 16 17 func TestBetaProb(t *testing.T) { 18 t.Parallel() 19 // Values a comparison with scipy 20 for _, test := range []struct { 21 x, alpha, beta, want float64 22 }{ 23 {0.1, 2, 0.5, 0.079056941504209499}, 24 {0.5, 1, 5.1, 0.29740426605235754}, 25 {0.1, 0.5, 0.5, 1.0610329539459691}, 26 {1, 0.5, 0.5, math.Inf(1)}, 27 {-1, 0.5, 0.5, 0}, 28 } { 29 pdf := Beta{Alpha: test.alpha, Beta: test.beta}.Prob(test.x) 30 if !scalar.EqualWithinAbsOrRel(pdf, test.want, 1e-10, 1e-10) { 31 t.Errorf("Pdf mismatch. Got %v, want %v", pdf, test.want) 32 } 33 } 34 } 35 36 func TestBetaRand(t *testing.T) { 37 t.Parallel() 38 src := rand.New(rand.NewSource(1)) 39 for i, b := range []Beta{ 40 {Alpha: 0.5, Beta: 0.5, Src: src}, 41 {Alpha: 5, Beta: 1, Src: src}, 42 {Alpha: 2, Beta: 2, Src: src}, 43 {Alpha: 2, Beta: 5, Src: src}, 44 } { 45 testBeta(t, b, i) 46 } 47 } 48 49 func testBeta(t *testing.T, b Beta, i int) { 50 const ( 51 tol = 1e-2 52 n = 1e5 53 bins = 10 54 ) 55 x := make([]float64, n) 56 generateSamples(x, b) 57 sort.Float64s(x) 58 59 testRandLogProbContinuous(t, i, 0, x, b, tol, bins) 60 checkMean(t, i, x, b, tol) 61 checkVarAndStd(t, i, x, b, tol) 62 checkExKurtosis(t, i, x, b, 5e-2) 63 checkEntropy(t, i, x, b, 5e-3) 64 checkProbContinuous(t, i, x, 0, 1, b, 1e-6) 65 checkQuantileCDFSurvival(t, i, x, b, tol) 66 checkProbQuantContinuous(t, i, x, b, tol) 67 68 if b.NumParameters() != 2 { 69 t.Errorf("Wrong number of parameters") 70 } 71 72 if b.CDF(-0.01) != 0 { 73 t.Errorf("CDF below 0 is not 0") 74 } 75 if b.CDF(0) != 0 { 76 t.Errorf("CDF at 0 is not 0") 77 } 78 if b.CDF(1) != 1 { 79 t.Errorf("CDF at 1 is not 1") 80 } 81 if b.CDF(1.01) != 1 { 82 t.Errorf("CDF above 1 is not 1") 83 } 84 85 if b.Survival(-0.01) != 1 { 86 t.Errorf("Survival below 0 is not 1") 87 } 88 if b.Survival(0) != 1 { 89 t.Errorf("Survival at 0 is not 1") 90 } 91 if b.Survival(1) != 0 { 92 t.Errorf("Survival at 1 is not 0") 93 } 94 if b.Survival(1.01) != 0 { 95 t.Errorf("Survival above 1 is not 0") 96 } 97 } 98 99 func TestBetaBadParams(t *testing.T) { 100 t.Parallel() 101 src := rand.New(rand.NewSource(1)) 102 for _, alpha := range []float64{0, -0.1} { 103 testBetaBadParams(t, alpha, 1, src) 104 testBetaBadParams(t, 1, alpha, src) 105 for _, beta := range []float64{0, -0.1} { 106 testBetaBadParams(t, alpha, beta, src) 107 } 108 } 109 } 110 111 func testBetaBadParams(t *testing.T, alpha float64, beta float64, src rand.Source) { 112 b := Beta{alpha, beta, src} 113 if !panics(func() { b.Entropy() }) { 114 t.Errorf("Entropy did not panic for Beta(%g, %g)", alpha, beta) 115 } 116 if !panics(func() { b.LogProb(0.5) }) { 117 t.Errorf("LogProb did not panic for Beta(%g, %g)", alpha, beta) 118 } 119 } 120 121 func TestBetaMode(t *testing.T) { 122 t.Parallel() 123 for _, test := range []struct { 124 alpha, beta, want float64 125 }{ 126 {1, 2, 0}, 127 {0.5, 2, 0}, 128 {2, 1, 1}, 129 {2, 0.5, 1}, 130 {4, 5, 3. / 7.}, 131 } { 132 mode := Beta{Alpha: test.alpha, Beta: test.beta}.Mode() 133 if !scalar.EqualWithinAbsOrRel(mode, test.want, 1e-10, 1e-10) { 134 t.Errorf("Mode mismatch for Beta(%g, %g). Got %v, want %g", test.alpha, test.beta, mode, test.want) 135 } 136 } 137 for _, test := range []struct { 138 alpha, beta float64 139 }{ 140 {1, 1}, 141 {0.5, 0.5}, 142 {1, 0.5}, 143 {0.5, 1}, 144 } { 145 mode := Beta{Alpha: test.alpha, Beta: test.beta}.Mode() 146 if !math.IsNaN(mode) { 147 t.Errorf("Mode is not NaN for Beta(%g, %g). Got: %v", test.alpha, test.beta, mode) 148 } 149 } 150 } 151 152 // See https://github.com/gonum/gonum/issues/1377 for details. 153 func TestBetaIssue1377(t *testing.T) { 154 t.Parallel() 155 b := Beta{Alpha: 1, Beta: 1} 156 p0 := b.Prob(0) 157 if p0 != 1 { 158 t.Errorf("Mismatch in PDF value at x == 0 for Alpha == 1 and Beta == 1: got %v, want 1", p0) 159 } 160 p1 := b.Prob(1) 161 if p1 != 1 { 162 t.Errorf("Mismatch in PDF value at x == 1 for Alpha == 1 and Beta == 1: got %v, want 1", p1) 163 } 164 b = Beta{Alpha: 1, Beta: 10} 165 p0 = b.Prob(0) 166 if math.IsNaN(p0) { 167 t.Errorf("NaN PDF at x == 0 for Alpha == 1 and Beta > 10") 168 } 169 b = Beta{Alpha: 10, Beta: 1} 170 p1 = b.Prob(1) 171 if math.IsNaN(p1) { 172 t.Errorf("NaN PDF at x == 1 for Alpha > 1 and Beta == 1") 173 } 174 }