gonum.org/v1/gonum@v0.14.0/stat/distuv/alphastable_test.go (about) 1 // Copyright ©2020 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/stat" 14 ) 15 16 func TestAlphaStable(t *testing.T) { 17 t.Parallel() 18 src := rand.New(rand.NewSource(1)) 19 for i, dist := range []AlphaStable{ 20 {Alpha: 0.5, Beta: 0, C: 1, Mu: 0, Src: src}, 21 {Alpha: 1, Beta: 0, C: 1, Mu: 0, Src: src}, 22 {Alpha: 2, Beta: 0, C: 1, Mu: 0, Src: src}, 23 {Alpha: 0.5, Beta: 1, C: 1, Mu: 0, Src: src}, 24 {Alpha: 1, Beta: 1, C: 1, Mu: 0, Src: src}, 25 {Alpha: 2, Beta: 1, C: 1, Mu: 0, Src: src}, 26 {Alpha: 0.5, Beta: 0, C: 1, Mu: 1, Src: src}, 27 {Alpha: 1, Beta: 0, C: 1, Mu: 1, Src: src}, 28 {Alpha: 2, Beta: 0, C: 1, Mu: 1, Src: src}, 29 {Alpha: 0.5, Beta: 0.5, C: 1, Mu: 1, Src: src}, 30 {Alpha: 1, Beta: 0.5, C: 1, Mu: 1, Src: src}, 31 {Alpha: 1.1, Beta: 0.5, C: 1, Mu: 1, Src: src}, 32 {Alpha: 2, Beta: 0.5, C: 1, Mu: 1, Src: src}, 33 } { 34 testAlphaStableAnalytic(t, i, dist) 35 } 36 } 37 38 func TestAlphaStability(t *testing.T) { 39 t.Parallel() 40 const ( 41 n = 10000 42 ksTol = 2e-2 43 ) 44 for i, test := range []struct { 45 alpha, beta1, beta2, c1, c2, mu1, mu2 float64 46 }{ 47 {2, 0, 0, 1, 2, 0.5, 0.25}, 48 {2, 0.9, -0.4, 1, 2, 0.5, 0.25}, 49 {1.9, 0, 0, 1, 2, 0.5, 0.25}, 50 {1, 0, 0, 1, 2, 0.5, 0.25}, 51 {1, -0.5, 0.5, 1, 2, 0.5, 0.25}, 52 {0.5, 0, 0, 1, 2, 0.5, 0.25}, 53 {0.5, -0.5, 0.5, 1, 2, 0.5, 0.25}, 54 } { 55 testStability(t, i, n, test.alpha, test.beta1, test.beta2, test.c1, test.c2, test.mu1, test.mu2, ksTol) 56 } 57 } 58 59 func TestAlphaStableGaussian(t *testing.T) { 60 t.Parallel() 61 src := rand.New(rand.NewSource(1)) 62 d := AlphaStable{Alpha: 2, Beta: 0, C: 1.5, Mu: -0.4, Src: src} 63 n := 100000 64 x := make([]float64, n) 65 for i := 0; i < n; i++ { 66 x[i] = d.Rand() 67 } 68 checkSkewness(t, 0, x, d, 1e-2) 69 checkExKurtosis(t, 0, x, d, 1e-2) 70 checkMean(t, 0, x, d, 1e-2) 71 checkVarAndStd(t, 0, x, d, 1e-2) 72 checkMode(t, 0, x, d, 5e-2, 1e-1) 73 } 74 75 func TestAlphaStableMean(t *testing.T) { 76 t.Parallel() 77 src := rand.New(rand.NewSource(1)) 78 d := AlphaStable{Alpha: 1.75, Beta: 0.2, C: 1.2, Mu: 0.3, Src: src} 79 n := 100000 80 x := make([]float64, n) 81 for i := 0; i < n; i++ { 82 x[i] = d.Rand() 83 } 84 checkMean(t, 0, x, d, 1e-2) 85 } 86 87 func TestAlphaStableCauchy(t *testing.T) { 88 t.Parallel() 89 src := rand.New(rand.NewSource(1)) 90 d := AlphaStable{Alpha: 1, Beta: 0, C: 1, Mu: 0, Src: src} 91 n := 1000000 92 x := make([]float64, n) 93 for i := 0; i < n; i++ { 94 x[i] = d.Rand() 95 } 96 checkMode(t, 0, x, d, 1e-2, 5e-2) 97 } 98 99 func testAlphaStableAnalytic(t *testing.T, i int, dist AlphaStable) { 100 if dist.NumParameters() != 4 { 101 t.Errorf("%d: expected NumParameters == 4, got %v", i, dist.NumParameters()) 102 } 103 if dist.Beta == 0 { 104 if dist.Mode() != dist.Mu { 105 t.Errorf("%d: expected Mode == Mu for Beta == 0, got %v", i, dist.Mode()) 106 } 107 if dist.Median() != dist.Mu { 108 t.Errorf("%d: expected Median == Mu for Beta == 0, got %v", i, dist.Median()) 109 } 110 } else { 111 if !panics(func() { dist.Mode() }) { 112 t.Errorf("%d: expected Mode to panic for Beta != 0", i) 113 } 114 if !panics(func() { dist.Median() }) { 115 t.Errorf("%d: expected Median to panic for Beta != 0", i) 116 } 117 } 118 if dist.Alpha > 1 { 119 if dist.Mean() != dist.Mu { 120 t.Errorf("%d: expected Mean == Mu for Alpha > 1, got %v", i, dist.Mean()) 121 } 122 } else { 123 if !math.IsNaN(dist.Mean()) { 124 t.Errorf("%d: expected NaN Mean for Alpha <= 1, got %v", i, dist.Mean()) 125 } 126 } 127 if dist.Alpha == 2 { 128 got := dist.Variance() 129 want := 2 * dist.C * dist.C 130 if got != want { 131 t.Errorf("%d: mismatch in Variance for Alpha == 2: got %v, want %g", i, got, want) 132 } 133 got = dist.StdDev() 134 want = math.Sqrt(2) * dist.C 135 if got != want { 136 t.Errorf("%d: mismatch in StdDev for Alpha == 2: got %v, want %g", i, got, want) 137 } 138 got = dist.Skewness() 139 want = 0 140 if got != want { 141 t.Errorf("%d: mismatch in Skewness for Alpha == 2: got %v, want %g", i, got, want) 142 } 143 got = dist.ExKurtosis() 144 want = 0 145 if got != want { 146 t.Errorf("%d: mismatch in ExKurtosis for Alpha == 2: got %v, want %g", i, got, want) 147 } 148 } else { 149 got := dist.Variance() 150 if !math.IsInf(got, 1) { 151 t.Errorf("%d: Variance is not +Inf for Alpha != 2: got %v", i, got) 152 } 153 got = dist.StdDev() 154 if !math.IsInf(got, 1) { 155 t.Errorf("%d: StdDev is not +Inf for Alpha != 2: got %v", i, got) 156 } 157 got = dist.Skewness() 158 if !math.IsNaN(got) { 159 t.Errorf("%d: Skewness is not NaN for Alpha != 2: got %v", i, got) 160 } 161 got = dist.ExKurtosis() 162 if !math.IsNaN(got) { 163 t.Errorf("%d: ExKurtosis is not NaN for Alpha != 2: got %v", i, got) 164 } 165 } 166 } 167 168 func testStability(t *testing.T, i, n int, alpha, beta1, beta2, c1, c2, mu1, mu2, ksTol float64) { 169 src := rand.New(rand.NewSource(1)) 170 d1 := AlphaStable{alpha, beta1, c1, mu1, src} 171 d2 := AlphaStable{alpha, beta2, c2, mu2, src} 172 c := math.Pow(math.Pow(c1, alpha)+math.Pow(c2, alpha), 1/alpha) 173 beta := (beta1*math.Pow(c1, alpha) + beta2*math.Pow(c2, alpha)) / math.Pow(c, alpha) 174 // Sum of d1 and d2. 175 d := AlphaStable{alpha, beta, c, mu1 + mu2, src} 176 sample1 := make([]float64, n) 177 sample2 := make([]float64, n) 178 for i := 0; i < n; i++ { 179 sample1[i] = d1.Rand() + d2.Rand() 180 sample2[i] = d.Rand() 181 } 182 sort.Float64s(sample1) 183 sort.Float64s(sample2) 184 ks := stat.KolmogorovSmirnov(sample1, nil, sample2, nil) 185 if ks > ksTol { 186 t.Errorf("%d: Kolmogorov-Smirnov distance %g exceeding tolerance %g", i, ks, ksTol) 187 } 188 }