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  }