gonum.org/v1/gonum@v0.14.0/stat/distuv/laplace_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 "gonum.org/v1/gonum/floats/scalar" 14 ) 15 16 func TestLaplaceProb(t *testing.T) { 17 t.Parallel() 18 pts := []univariateProbPoint{ 19 { 20 loc: 0, 21 prob: 0.5, 22 cumProb: 0.5, 23 logProb: math.Log(0.5), 24 }, 25 { 26 loc: -1, 27 prob: 1 / (2 * math.E), 28 cumProb: 0.1839397205857211607977618850807304337229055655158839172539184008487307478724499016785736371729598219, 29 logProb: math.Log(1 / (2 * math.E)), 30 }, 31 { 32 loc: 1, 33 prob: 1 / (2 * math.E), 34 cumProb: 0.8160602794142788392022381149192695662770944344841160827460815991512692521275500983214263628270401781, 35 logProb: math.Log(1 / (2 * math.E)), 36 }, 37 { 38 loc: -7, 39 prob: 1 / (2 * math.Pow(math.E, 7)), 40 cumProb: 0.0004559409827772581040015680422046413132368622637180269204080667109447399446551532646631395032324502210, 41 logProb: math.Log(1 / (2 * math.Pow(math.E, 7))), 42 }, 43 { 44 loc: 7, 45 prob: 1 / (2 * math.Pow(math.E, 7)), 46 cumProb: 0.9995440590172227418959984319577953586867631377362819730795919332890552600553448467353368604967675498, 47 logProb: math.Log(1 / (2 * math.Pow(math.E, 7))), 48 }, 49 { 50 loc: -20, 51 prob: math.Exp(-20.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641869), 52 cumProb: 1.030576811219278913982970190077910488187903637799551846486122330814582011892279676639955463952790684 * 1e-9, 53 logProb: -20.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641869, 54 }, 55 { 56 loc: 20, 57 prob: math.Exp(-20.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641869), 58 cumProb: 0.999999998969423188780721086017029809922089511812096362200448153513877669185417988107720323360044536, 59 logProb: -20.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641869, 60 }, 61 } 62 testDistributionProbs(t, Laplace{Mu: 0, Scale: 1}, "Laplace", pts) 63 } 64 65 func TestLaplace(t *testing.T) { 66 t.Parallel() 67 src := rand.New(rand.NewSource(1)) 68 for i, dist := range []Laplace{ 69 {Mu: 0, Scale: 3, Src: src}, 70 {Mu: 1, Scale: 1.5, Src: src}, 71 {Mu: -1, Scale: 0.9, Src: src}, 72 } { 73 testLaplace(t, dist, i) 74 } 75 } 76 77 func testLaplace(t *testing.T, dist Laplace, i int) { 78 const ( 79 tol = 1e-2 80 n = 3e6 81 bins = 50 82 ) 83 x := make([]float64, n) 84 generateSamples(x, dist) 85 sort.Float64s(x) 86 87 checkMean(t, i, x, dist, tol) 88 checkVarAndStd(t, i, x, dist, tol) 89 checkEntropy(t, i, x, dist, tol) 90 checkExKurtosis(t, i, x, dist, tol) 91 checkSkewness(t, i, x, dist, tol) 92 checkMedian(t, i, x, dist, tol) 93 checkQuantileCDFSurvival(t, i, x, dist, tol) 94 checkProbContinuous(t, i, x, math.Inf(-1), math.Inf(1), dist, 1e-10) 95 checkProbQuantContinuous(t, i, x, dist, tol) 96 testDerivParam(t, &dist) 97 98 if dist.Mu != dist.Mode() { 99 t.Errorf("Mismatch in mode value, got: %v, want: %g", dist.Mode(), dist.Mu) 100 } 101 score := dist.Score(nil, dist.Mu) 102 if !math.IsNaN(score[0]) { 103 t.Errorf("Expected NaN score over Mu for x == Mu, got %v", score[0]) 104 } 105 if score[1] != -1/dist.Scale { 106 t.Errorf("Mismatch in score over Scale value for x == Mu, got: %v, want: %g", score[1], -1/dist.Scale) 107 } 108 scoreInput := dist.ScoreInput(dist.Mu) 109 if !math.IsNaN(scoreInput) { 110 t.Errorf("Expected NaN input score for x == Mu, got %v", scoreInput) 111 } 112 } 113 114 func TestLaplaceFit(t *testing.T) { 115 t.Parallel() 116 cases := []struct { 117 samples []float64 118 weights []float64 119 wantMu float64 120 wantScale float64 121 }{ 122 { 123 samples: []float64{10, 1, 1}, 124 weights: nil, 125 wantMu: 1, 126 wantScale: 3, 127 }, 128 { 129 samples: []float64{10, 1, 1}, 130 weights: []float64{10, 10, 10}, 131 wantMu: 1, 132 wantScale: 3, 133 }, 134 { 135 samples: []float64{10, 1, 1}, 136 weights: []float64{0, 1, 1}, 137 wantMu: 1, 138 wantScale: 0, 139 }, 140 { 141 samples: []float64{1, 1, 10}, 142 weights: []float64{1, 1, 0}, 143 wantMu: 1, 144 wantScale: 0, 145 }, 146 { 147 samples: []float64{10}, 148 weights: nil, 149 wantMu: 10, 150 wantScale: 0, 151 }, 152 } 153 for i, test := range cases { 154 d := Laplace{} 155 d.Fit(test.samples, test.weights) 156 if !scalar.EqualWithinAbsOrRel(d.Mu, test.wantMu, 1e-10, 1e-10) { 157 t.Errorf("unexpected location result for test %d: got:%f, want:%f", i, d.Mu, test.wantMu) 158 } 159 if !scalar.EqualWithinAbsOrRel(d.Scale, test.wantScale, 1e-10, 1e-10) { 160 t.Errorf("unexpected scale result for test %d: got:%f, want:%f", i, d.Scale, test.wantScale) 161 } 162 } 163 } 164 165 func TestLaplaceFitRandomSamples(t *testing.T) { 166 t.Parallel() 167 168 nSamples := 100000 169 src := rand.New(rand.NewSource(1)) 170 l := Laplace{ 171 Mu: 3, 172 Scale: 5, 173 Src: src, 174 } 175 samples := make([]float64, nSamples) 176 for i := range samples { 177 samples[i] = l.Rand() 178 } 179 le := Laplace{} 180 le.Fit(samples, nil) 181 if !scalar.EqualWithinAbsOrRel(le.Mu, l.Mu, 1e-2, 1e-2) { 182 t.Errorf("unexpected location result for random test got:%f, want:%f", le.Mu, l.Mu) 183 } 184 if !scalar.EqualWithinAbsOrRel(le.Scale, l.Scale, 1e-2, 1e-2) { 185 t.Errorf("unexpected scale result for random test got:%f, want:%f", le.Scale, l.Scale) 186 } 187 } 188 189 func TestLaplaceFitPanic(t *testing.T) { 190 t.Parallel() 191 l := Laplace{ 192 Mu: 3, 193 Scale: 5, 194 Src: nil, 195 } 196 if !panics(func() { l.Fit([]float64{1, 1, 1}, []float64{0.4, 0.4}) }) { 197 t.Errorf("Expected panic in Fit for len(sample) != len(weights)") 198 } 199 if !panics(func() { l.Fit([]float64{}, nil) }) { 200 t.Errorf("Expected panic in Fit for len(sample) == 0") 201 } 202 }