gonum.org/v1/gonum@v0.14.0/stat/distuv/norm_test.go (about) 1 // Copyright ©2014 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" 15 "gonum.org/v1/gonum/floats/scalar" 16 ) 17 18 // TestNormalProbs tests LogProb, Prob, CumProb, and Quantile 19 func TestNormalProbs(t *testing.T) { 20 t.Parallel() 21 pts := []univariateProbPoint{ 22 { 23 loc: 0, 24 prob: oneOverRoot2Pi, 25 cumProb: 0.5, 26 logProb: -0.91893853320467274178032973640561763986139747363778341281715, 27 }, 28 { 29 loc: -1, 30 prob: 0.2419707245191433497978301929355606548286719707374350254875550842811000635700832945083112946939424047, 31 cumProb: 0.158655253931457051414767454367962077522087033273395609012605, 32 logProb: math.Log(0.2419707245191433497978301929355606548286719707374350254875550842811000635700832945083112946939424047), 33 }, 34 { 35 loc: 1, 36 prob: 0.2419707245191433497978301929355606548286719707374350254875550842811000635700832945083112946939424047, 37 cumProb: 0.841344746068542948585232545632037922477912966726604390987394, 38 logProb: math.Log(0.2419707245191433497978301929355606548286719707374350254875550842811000635700832945083112946939424047), 39 }, 40 { 41 loc: -7, 42 prob: 9.134720408364593342868613916794233023000190834851937054490546361277622761970225469305158915808284566e-12, 43 cumProb: 1.279812543885835004383623690780832998032844154198717929e-12, 44 logProb: math.Log(9.134720408364593342868613916794233023000190834851937054490546361277622761970225469305158915808284566e-12), 45 }, 46 { 47 loc: 7, 48 prob: 9.134720408364593342868613916794233023000190834851937054490546361277622761970225469305158915808284566e-12, 49 cumProb: 0.99999999999872018745611416499561637630921916700196715584580, 50 logProb: math.Log(9.134720408364593342868613916794233023000190834851937054490546361277622761970225469305158915808284566e-12), 51 }, 52 } 53 testDistributionProbs(t, Normal{Mu: 0, Sigma: 1}, "normal", pts) 54 55 pts = []univariateProbPoint{ 56 { 57 loc: 2, 58 prob: 0.07978845608028653558798921198687637369517172623298693153318516593413158517986036770025046678146138729, 59 cumProb: 0.5, 60 logProb: math.Log(0.07978845608028653558798921198687637369517172623298693153318516593413158517986036770025046678146138729), 61 }, 62 { 63 loc: -3, 64 prob: 0.04839414490382866995956603858711213096573439414748700509751101685622001271401665890166225893878848095, 65 cumProb: 0.158655253931457051414767454367962077522087033273395609012605, 66 logProb: math.Log(0.04839414490382866995956603858711213096573439414748700509751101685622001271401665890166225893878848095), 67 }, 68 { 69 loc: 7, 70 prob: 0.04839414490382866995956603858711213096573439414748700509751101685622001271401665890166225893878848095, 71 cumProb: 0.841344746068542948585232545632037922477912966726604390987394, 72 logProb: math.Log(0.04839414490382866995956603858711213096573439414748700509751101685622001271401665890166225893878848095), 73 }, 74 { 75 loc: -33, 76 prob: 1.826944081672918668573722783358846604600038166970387410898109272255524552394045093861031783161656913e-12, 77 cumProb: 1.279812543885835004383623690780832998032844154198717929e-12, 78 logProb: math.Log(1.826944081672918668573722783358846604600038166970387410898109272255524552394045093861031783161656913e-12), 79 }, 80 { 81 loc: 37, 82 prob: 1.826944081672918668573722783358846604600038166970387410898109272255524552394045093861031783161656913e-12, 83 cumProb: 0.99999999999872018745611416499561637630921916700196715584580, 84 logProb: math.Log(1.826944081672918668573722783358846604600038166970387410898109272255524552394045093861031783161656913e-12), 85 }, 86 } 87 testDistributionProbs(t, Normal{Mu: 2, Sigma: 5}, "normal", pts) 88 } 89 90 func TestNormal(t *testing.T) { 91 t.Parallel() 92 src := rand.New(rand.NewSource(1)) 93 for i, dist := range []Normal{ 94 {Mu: 0, Sigma: 3, Src: src}, 95 {Mu: 1, Sigma: 1.5, Src: src}, 96 {Mu: -1, Sigma: 0.9, Src: src}, 97 } { 98 testNormal(t, dist, i) 99 } 100 } 101 102 func testNormal(t *testing.T, dist Normal, i int) { 103 const ( 104 tol = 1e-2 105 n = 3e6 106 bins = 50 107 ) 108 x := make([]float64, n) 109 generateSamples(x, dist) 110 sort.Float64s(x) 111 112 checkMean(t, i, x, dist, tol) 113 checkVarAndStd(t, i, x, dist, tol) 114 checkEntropy(t, i, x, dist, tol) 115 checkExKurtosis(t, i, x, dist, tol) 116 checkSkewness(t, i, x, dist, tol) 117 checkMedian(t, i, x, dist, tol) 118 checkQuantileCDFSurvival(t, i, x, dist, tol) 119 checkProbContinuous(t, i, x, math.Inf(-1), math.Inf(1), dist, 1e-10) 120 checkProbQuantContinuous(t, i, x, dist, tol) 121 122 if dist.Mu != dist.Mode() { 123 t.Errorf("Mismatch in mode value: got %v, want %g", dist.Mode(), dist.Mu) 124 } 125 } 126 127 func TestNormFitPrior(t *testing.T) { 128 t.Parallel() 129 testConjugateUpdate(t, func() ConjugateUpdater { return &Normal{Mu: -10, Sigma: 6} }) 130 } 131 132 func TestNormScore(t *testing.T) { 133 t.Parallel() 134 for _, test := range []*Normal{ 135 { 136 Mu: 0, 137 Sigma: 1, 138 }, 139 { 140 Mu: 0.32238, 141 Sigma: 13.69, 142 }, 143 } { 144 testDerivParam(t, test) 145 } 146 } 147 148 func TestNormalQuantile(t *testing.T) { 149 t.Parallel() 150 // Values from https://www.johndcook.com/blog/normal_cdf_inverse/ 151 p := []float64{ 152 0.0000001, 153 0.00001, 154 0.001, 155 0.05, 156 0.15, 157 0.25, 158 0.35, 159 0.45, 160 0.55, 161 0.65, 162 0.75, 163 0.85, 164 0.95, 165 0.999, 166 0.99999, 167 0.9999999, 168 } 169 ans := []float64{ 170 -5.199337582187471, 171 -4.264890793922602, 172 -3.090232306167813, 173 -1.6448536269514729, 174 -1.0364333894937896, 175 -0.6744897501960817, 176 -0.38532046640756773, 177 -0.12566134685507402, 178 0.12566134685507402, 179 0.38532046640756773, 180 0.6744897501960817, 181 1.0364333894937896, 182 1.6448536269514729, 183 3.090232306167813, 184 4.264890793922602, 185 5.199337582187471, 186 } 187 for i, v := range p { 188 got := UnitNormal.Quantile(v) 189 if !scalar.EqualWithinAbsOrRel(got, ans[i], 1e-10, 1e-10) { 190 t.Errorf("Quantile mismatch. Case %d, want: %v, got: %v", i, ans[i], got) 191 } 192 } 193 } 194 195 func TestNormFitPanic(t *testing.T) { 196 t.Parallel() 197 n := Normal{Mu: 0, Sigma: 1} 198 defer func() { 199 r := recover() 200 if r != nil { 201 t.Errorf("unexpected panic for Fit call: %v", r) 202 } 203 }() 204 n.Fit(make([]float64, 10), nil) 205 } 206 207 func BenchmarkNormalQuantile(b *testing.B) { 208 n := Normal{Mu: 2, Sigma: 3.1} 209 ps := make([]float64, 1000) // ensure there are small values 210 floats.Span(ps, 0, 1) 211 for i := 0; i < b.N; i++ { 212 for _, v := range ps { 213 x := n.Quantile(v) 214 _ = x 215 } 216 } 217 } 218 219 // See https://github.com/gonum/gonum/issues/577 for details. 220 func TestNormalIssue577(t *testing.T) { 221 t.Parallel() 222 x := -36.0 223 max := 1.e-282 224 cdf := Normal{Mu: 0, Sigma: 1}.CDF(x) 225 if cdf <= 0 { 226 t.Errorf("Normal{0,1}.CDF(%e) should be positive. got: %e", x, cdf) 227 } 228 if cdf > max { 229 t.Errorf("Normal{0,1}.CDF(%e) is greater than %e. got: %e", x, max, cdf) 230 } 231 }