blob: 0179e17301b47c65db613a8b8dcf5c91e72e4572 [file] [log] [blame] [edit]
// Copyright ©2014 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package distuv
import (
"math"
"testing"
"gonum.org/v1/gonum/floats"
)
// TestNormalProbs tests LogProb, Prob, CumProb, and Quantile
func TestNormalProbs(t *testing.T) {
pts := []univariateProbPoint{
{
loc: 0,
prob: oneOverRoot2Pi,
cumProb: 0.5,
logProb: -0.91893853320467274178032973640561763986139747363778341281715,
},
{
loc: -1,
prob: 0.2419707245191433497978301929355606548286719707374350254875550842811000635700832945083112946939424047,
cumProb: 0.158655253931457051414767454367962077522087033273395609012605,
logProb: math.Log(0.2419707245191433497978301929355606548286719707374350254875550842811000635700832945083112946939424047),
},
{
loc: 1,
prob: 0.2419707245191433497978301929355606548286719707374350254875550842811000635700832945083112946939424047,
cumProb: 0.841344746068542948585232545632037922477912966726604390987394,
logProb: math.Log(0.2419707245191433497978301929355606548286719707374350254875550842811000635700832945083112946939424047),
},
{
loc: -7,
prob: 9.134720408364593342868613916794233023000190834851937054490546361277622761970225469305158915808284566e-12,
cumProb: 1.279812543885835004383623690780832998032844154198717929e-12,
logProb: math.Log(9.134720408364593342868613916794233023000190834851937054490546361277622761970225469305158915808284566e-12),
},
{
loc: 7,
prob: 9.134720408364593342868613916794233023000190834851937054490546361277622761970225469305158915808284566e-12,
cumProb: 0.99999999999872018745611416499561637630921916700196715584580,
logProb: math.Log(9.134720408364593342868613916794233023000190834851937054490546361277622761970225469305158915808284566e-12),
},
}
testDistributionProbs(t, Normal{Mu: 0, Sigma: 1}, "normal", pts)
pts = []univariateProbPoint{
{
loc: 2,
prob: 0.07978845608028653558798921198687637369517172623298693153318516593413158517986036770025046678146138729,
cumProb: 0.5,
logProb: math.Log(0.07978845608028653558798921198687637369517172623298693153318516593413158517986036770025046678146138729),
},
{
loc: -3,
prob: 0.04839414490382866995956603858711213096573439414748700509751101685622001271401665890166225893878848095,
cumProb: 0.158655253931457051414767454367962077522087033273395609012605,
logProb: math.Log(0.04839414490382866995956603858711213096573439414748700509751101685622001271401665890166225893878848095),
},
{
loc: 7,
prob: 0.04839414490382866995956603858711213096573439414748700509751101685622001271401665890166225893878848095,
cumProb: 0.841344746068542948585232545632037922477912966726604390987394,
logProb: math.Log(0.04839414490382866995956603858711213096573439414748700509751101685622001271401665890166225893878848095),
},
{
loc: -33,
prob: 1.826944081672918668573722783358846604600038166970387410898109272255524552394045093861031783161656913e-12,
cumProb: 1.279812543885835004383623690780832998032844154198717929e-12,
logProb: math.Log(1.826944081672918668573722783358846604600038166970387410898109272255524552394045093861031783161656913e-12),
},
{
loc: 37,
prob: 1.826944081672918668573722783358846604600038166970387410898109272255524552394045093861031783161656913e-12,
cumProb: 0.99999999999872018745611416499561637630921916700196715584580,
logProb: math.Log(1.826944081672918668573722783358846604600038166970387410898109272255524552394045093861031783161656913e-12),
},
}
testDistributionProbs(t, Normal{Mu: 2, Sigma: 5}, "normal", pts)
}
func TestNormFitPrior(t *testing.T) {
testConjugateUpdate(t, func() ConjugateUpdater { return &Normal{Mu: -10, Sigma: 6} })
}
func TestNormScore(t *testing.T) {
for _, test := range []*Normal{
{
Mu: 0,
Sigma: 1,
},
{
Mu: 0.32238,
Sigma: 13.69,
},
} {
testDerivParam(t, test)
}
}
func TestNormalQuantile(t *testing.T) {
// Values from https://www.johndcook.com/blog/normal_cdf_inverse/
p := []float64{
0.0000001,
0.00001,
0.001,
0.05,
0.15,
0.25,
0.35,
0.45,
0.55,
0.65,
0.75,
0.85,
0.95,
0.999,
0.99999,
0.9999999,
}
ans := []float64{
-5.199337582187471,
-4.264890793922602,
-3.090232306167813,
-1.6448536269514729,
-1.0364333894937896,
-0.6744897501960817,
-0.38532046640756773,
-0.12566134685507402,
0.12566134685507402,
0.38532046640756773,
0.6744897501960817,
1.0364333894937896,
1.6448536269514729,
3.090232306167813,
4.264890793922602,
5.199337582187471,
}
for i, v := range p {
got := UnitNormal.Quantile(v)
if !floats.EqualWithinAbsOrRel(got, ans[i], 1e-10, 1e-10) {
t.Errorf("Quantile mismatch. Case %d, want: %v, got: %v", i, ans[i], got)
}
}
}
func TestNormFitPanic(t *testing.T) {
n := Normal{Mu: 0, Sigma: 1}
defer func() {
r := recover()
if r != nil {
t.Errorf("unexpected panic for Fit call: %v", r)
}
}()
n.Fit(make([]float64, 10), nil)
}
func BenchmarkNormalQuantile(b *testing.B) {
n := Normal{Mu: 2, Sigma: 3.1}
ps := make([]float64, 1000) // ensure there are small values
floats.Span(ps, 0, 1)
for i := 0; i < b.N; i++ {
for _, v := range ps {
x := n.Quantile(v)
_ = x
}
}
}