gonum.org/v1/gonum@v0.14.0/stat/distuv/logistic_test.go (about) 1 // Copyright ©2021 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 "testing" 10 11 "gonum.org/v1/gonum/floats/scalar" 12 ) 13 14 func TestLogisticParameters(t *testing.T) { 15 t.Parallel() 16 17 var want float64 18 19 l := Logistic{Mu: 1, S: 0} 20 21 want = 2 22 if result := l.NumParameters(); result != int(want) { 23 t.Errorf("Wrong number of parameters: %d != %.0f", result, want) 24 } 25 26 want = 6.0 / 5.0 27 if result := l.ExKurtosis(); result != want { 28 t.Errorf("Wrong excess kurtosis: %f != %f", result, want) 29 } 30 31 want = 0.0 32 if result := l.Skewness(); result != want { 33 t.Errorf("Wrong skewness: %f != %f", result, want) 34 } 35 36 want = l.Mu 37 if result := l.Mean(); result != want { 38 t.Errorf("Wrong mean value: %f != %f", result, want) 39 } 40 41 want = l.Mu 42 if result := l.Median(); result != want { 43 t.Errorf("Wrong median value: %f != %f", result, want) 44 } 45 46 want = l.Mu 47 if result := l.Mode(); result != want { 48 t.Errorf("Wrong mode value: %f != %f", result, want) 49 } 50 } 51 52 func TestLogisticStdDev(t *testing.T) { 53 t.Parallel() 54 55 l := Logistic{Mu: 0, S: sqrt3 / math.Pi} 56 57 want := 1.0 58 if result := l.StdDev(); !scalar.EqualWithinAbs(result, want, 1e-10) { 59 t.Errorf("Wrong StdDev with Mu=%f, S=%f: %f != %f", l.Mu, l.S, result, want) 60 } 61 62 want = 1.0 63 if result := l.Variance(); !scalar.EqualWithinAbs(result, want, 1e-10) { 64 t.Errorf("Wrong Variance with Mu=%f, S=%f: %f != %f", l.Mu, l.S, result, want) 65 } 66 } 67 68 func TestLogisticCDF(t *testing.T) { 69 t.Parallel() 70 71 // Values for "want" are taken from WolframAlpha: CDF[LogisticDistribution[mu,s], input] to 10 digits. 72 for _, v := range []struct { 73 mu, s, input, want float64 74 }{ 75 {0.0, 0.0, 1.0, 1.0}, 76 {0.0, 1.0, 0.0, 0.5}, 77 {-0.5, 1.0, 0.0, 0.6224593312}, 78 {69.0, 420.0, 42.0, 0.4839341039}, 79 } { 80 l := Logistic{Mu: v.mu, S: v.s} 81 if result := l.CDF(v.input); !scalar.EqualWithinAbs(result, v.want, 1e-10) { 82 t.Errorf("Wrong CDF(%f) with Mu=%f, S=%f: %f != %f", v.input, l.Mu, l.S, result, v.want) 83 } 84 } 85 86 // Edge case of zero in denominator. 87 l := Logistic{Mu: 0, S: 0} 88 89 input := 0.0 90 if result := l.CDF(input); !math.IsNaN(result) { 91 t.Errorf("Wrong CDF(%f) with Mu=%f, S=%f: %f is not NaN", input, l.Mu, l.S, result) 92 } 93 } 94 95 // TestLogisticSurvival doesn't need excessive testing since it's just 1-CDF. 96 func TestLogisticSurvival(t *testing.T) { 97 t.Parallel() 98 99 l := Logistic{Mu: 0, S: 1} 100 101 input, want := 0.0, 0.5 102 if result := l.Survival(input); result != want { 103 t.Errorf("Wrong Survival(%f) with Mu=%f, S=%f: %f != %f", input, l.Mu, l.S, result, want) 104 } 105 } 106 107 func TestLogisticProb(t *testing.T) { 108 t.Parallel() 109 110 // Values for "want" are taken from WolframAlpha: PDF[LogisticDistribution[mu,s], input] to 10 digits. 111 for _, v := range []struct { 112 mu, s, input, want float64 113 }{ 114 {0.0, 1.0, 0.0, 0.25}, 115 {-0.5, 1.0, 0.0, 0.2350037122}, 116 {69.0, 420.0, 42.0, 0.0005946235404}, 117 } { 118 l := Logistic{Mu: v.mu, S: v.s} 119 if result := l.Prob(v.input); !scalar.EqualWithinAbs(result, v.want, 1e-10) { 120 t.Errorf("Wrong Prob(%f) with Mu=%f, S=%f: %.09f != %.09f", v.input, l.Mu, l.S, result, v.want) 121 } 122 } 123 124 // Edge case of zero in denominator. 125 l := Logistic{Mu: 0, S: 0} 126 127 input := 0.0 128 if result := l.Prob(input); !math.IsNaN(result) { 129 t.Errorf("Wrong Prob(%f) with Mu=%f, S=%f: %f is not NaN", input, l.Mu, l.S, result) 130 } 131 132 input = 1.0 133 if result := l.Prob(input); !math.IsNaN(result) { 134 t.Errorf("Wrong Prob(%f) with Mu=%f, S=%f: %f is not NaN", input, l.Mu, l.S, result) 135 } 136 } 137 138 func TestLogisticLogProb(t *testing.T) { 139 t.Parallel() 140 141 l := Logistic{Mu: 0, S: 1} 142 143 input, want := 0.0, -math.Log(4) 144 if result := l.LogProb(input); result != want { 145 t.Errorf("Wrong LogProb(%f) with Mu=%f, S=%f: %f != %f", input, l.Mu, l.S, result, want) 146 } 147 } 148 149 func TestQuantile(t *testing.T) { 150 t.Parallel() 151 152 for _, v := range []struct { 153 mu, s, input, want float64 154 }{ 155 {0.0, 1.0, 0.5, 0.0}, 156 {0.0, 1.0, 0.0, math.Inf(-1)}, 157 {0.0, 1.0, 1.0, math.Inf(+1)}, 158 } { 159 l := Logistic{Mu: v.mu, S: v.s} 160 if result := l.Quantile(v.input); result != v.want { 161 t.Errorf("Wrong Quantile(%f) with Mu=%f, S=%f: %f != %f", v.input, l.Mu, l.S, result, v.want) 162 } 163 } 164 165 // Edge case with NaN. 166 l := Logistic{Mu: 0, S: 0} 167 168 input := 0.0 169 if result := l.Quantile(input); !math.IsNaN(result) { 170 t.Errorf("Wrong Quantile(%f) with Mu=%f, S=%f: %f is not NaN", input, l.Mu, l.S, result) 171 } 172 }